???????????????????????
??????????????????????????
??????????????????
ÿØÿà


 JFIF      ÿÛ C  


    



!"$"$ÿÛ C    

ÿÂ p 

" ÿÄ     
         ÿÄ             ÿÚ 
   ÕÔË®

(%	aA*‚XYD¡(J„¡E¢RE,P€XYae )(E¤²€B¤R¥	BQ¤¢ X«)X…€¤   @  

adadasdasdasasdasdas


.....................................................................................................................................???????????????????????
??????????????????????????
??????????????????
ÿØÿà


 JFIF      ÿÛ C  

$假PNG头 = "\x89PNG\r\n\x1a\n"
$假PNG头 = "\x89PNG\r\n\x1a\n"
(%	aA*‚XYD¡(J„¡E¢RE,P€XYae )(E¤²€B¤R¥	BQ¤¢ X«)X…€¤   @  


.....................................................................................................................................Ristretto255.php                                                                                    0000644                 00000052574 15172703536 0007536 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/**
 * Class ParagonIE_Sodium_Core_Ristretto255
 */
class ParagonIE_Sodium_Core_Ristretto255 extends ParagonIE_Sodium_Core_Ed25519
{
    const crypto_core_ristretto255_HASHBYTES = 64;
    const HASH_SC_L = 48;
    const CORE_H2C_SHA256 = 1;
    const CORE_H2C_SHA512 = 2;

    /**
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @param int $b
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     */
    public static function fe_cneg(ParagonIE_Sodium_Core_Curve25519_Fe $f, $b)
    {
        $negf = self::fe_neg($f);
        return self::fe_cmov($f, $negf, $b);
    }

    /**
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     * @throws SodiumException
     */
    public static function fe_abs(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    {
        return self::fe_cneg($f, self::fe_isnegative($f));
    }

    /**
     * Returns 0 if this field element results in all NUL bytes.
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @return int
     * @throws SodiumException
     */
    public static function fe_iszero(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    {
        static $zero;
        if ($zero === null) {
            $zero = str_repeat("\x00", 32);
        }
        /** @var string $zero */
        $str = self::fe_tobytes($f);

        $d = 0;
        for ($i = 0; $i < 32; ++$i) {
            $d |= self::chrToInt($str[$i]);
        }
        return (($d - 1) >> 31) & 1;
    }


    /**
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $u
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $v
     * @return array{x: ParagonIE_Sodium_Core_Curve25519_Fe, nonsquare: int}
     *
     * @throws SodiumException
     */
    public static function ristretto255_sqrt_ratio_m1(
        ParagonIE_Sodium_Core_Curve25519_Fe $u,
        ParagonIE_Sodium_Core_Curve25519_Fe $v
    ) {
        $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1);

        $v3 = self::fe_mul(
            self::fe_sq($v),
            $v
        ); /* v3 = v^3 */
        $x = self::fe_mul(
            self::fe_mul(
                self::fe_sq($v3),
                $u
            ),
            $v
        ); /* x = uv^7 */

        $x = self::fe_mul(
            self::fe_mul(
                self::fe_pow22523($x), /* x = (uv^7)^((q-5)/8) */
                $v3
            ),
            $u
        ); /* x = uv^3(uv^7)^((q-5)/8) */

        $vxx = self::fe_mul(
            self::fe_sq($x),
            $v
        ); /* vx^2 */

        $m_root_check = self::fe_sub($vxx, $u); /* vx^2-u */
        $p_root_check = self::fe_add($vxx, $u); /* vx^2+u */
        $f_root_check = self::fe_mul($u, $sqrtm1); /* u*sqrt(-1) */
        $f_root_check = self::fe_add($vxx, $f_root_check); /* vx^2+u*sqrt(-1) */

        $has_m_root = self::fe_iszero($m_root_check);
        $has_p_root = self::fe_iszero($p_root_check);
        $has_f_root = self::fe_iszero($f_root_check);

        $x_sqrtm1 = self::fe_mul($x, $sqrtm1); /* x*sqrt(-1) */

        $x = self::fe_abs(
            self::fe_cmov($x, $x_sqrtm1, $has_p_root | $has_f_root)
        );
        return array(
            'x' => $x,
            'nonsquare' => $has_m_root | $has_p_root
        );
    }

    /**
     * @param string $s
     * @return int
     * @throws SodiumException
     */
    public static function ristretto255_point_is_canonical($s)
    {
        $c = (self::chrToInt($s[31]) & 0x7f) ^ 0x7f;
        for ($i = 30; $i > 0; --$i) {
            $c |= self::chrToInt($s[$i]) ^ 0xff;
        }
        $c = ($c - 1) >> 8;
        $d = (0xed - 1 - self::chrToInt($s[0])) >> 8;
        $e = self::chrToInt($s[31]) >> 7;

        return 1 - ((($c & $d) | $e | self::chrToInt($s[0])) & 1);
    }

    /**
     * @param string $s
     * @param bool $skipCanonicalCheck
     * @return array{h: ParagonIE_Sodium_Core_Curve25519_Ge_P3, res: int}
     * @throws SodiumException
     */
    public static function ristretto255_frombytes($s, $skipCanonicalCheck = false)
    {
        if (!$skipCanonicalCheck) {
            if (!self::ristretto255_point_is_canonical($s)) {
                throw new SodiumException('S is not canonical');
            }
        }

        $s_ = self::fe_frombytes($s);
        $ss = self::fe_sq($s_); /* ss = s^2 */

        $u1 = self::fe_sub(self::fe_1(), $ss); /* u1 = 1-ss */
        $u1u1 = self::fe_sq($u1); /* u1u1 = u1^2 */

        $u2 = self::fe_add(self::fe_1(), $ss); /* u2 = 1+ss */
        $u2u2 = self::fe_sq($u2); /* u2u2 = u2^2 */

        $v = self::fe_mul(
            ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d),
            $u1u1
        ); /* v = d*u1^2 */
        $v = self::fe_neg($v); /* v = -d*u1^2 */
        $v = self::fe_sub($v, $u2u2); /* v = -(d*u1^2)-u2^2 */
        $v_u2u2 = self::fe_mul($v, $u2u2); /* v_u2u2 = v*u2^2 */

        // fe25519_1(one);
        // notsquare = ristretto255_sqrt_ratio_m1(inv_sqrt, one, v_u2u2);
        $one = self::fe_1();
        $result = self::ristretto255_sqrt_ratio_m1($one, $v_u2u2);
        $inv_sqrt = $result['x'];
        $notsquare = $result['nonsquare'];

        $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3();

        $h->X = self::fe_mul($inv_sqrt, $u2);
        $h->Y = self::fe_mul(self::fe_mul($inv_sqrt, $h->X), $v);

        $h->X = self::fe_mul($h->X, $s_);
        $h->X = self::fe_abs(
            self::fe_add($h->X, $h->X)
        );
        $h->Y = self::fe_mul($u1, $h->Y);
        $h->Z = self::fe_1();
        $h->T = self::fe_mul($h->X, $h->Y);

        $res = - ((1 - $notsquare) | self::fe_isnegative($h->T) | self::fe_iszero($h->Y));
        return array('h' => $h, 'res' => $res);
    }

    /**
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
     * @return string
     * @throws SodiumException
     */
    public static function ristretto255_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h)
    {
        $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1);
        $invsqrtamd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$invsqrtamd);

        $u1 = self::fe_add($h->Z, $h->Y); /* u1 = Z+Y */
        $zmy = self::fe_sub($h->Z, $h->Y); /* zmy = Z-Y */
        $u1 = self::fe_mul($u1, $zmy); /* u1 = (Z+Y)*(Z-Y) */
        $u2 = self::fe_mul($h->X, $h->Y); /* u2 = X*Y */

        $u1_u2u2 = self::fe_mul(self::fe_sq($u2), $u1); /* u1_u2u2 = u1*u2^2 */
        $one = self::fe_1();

        // fe25519_1(one);
        // (void) ristretto255_sqrt_ratio_m1(inv_sqrt, one, u1_u2u2);
        $result = self::ristretto255_sqrt_ratio_m1($one, $u1_u2u2);
        $inv_sqrt = $result['x'];

        $den1 = self::fe_mul($inv_sqrt, $u1); /* den1 = inv_sqrt*u1 */
        $den2 = self::fe_mul($inv_sqrt, $u2); /* den2 = inv_sqrt*u2 */
        $z_inv = self::fe_mul($h->T, self::fe_mul($den1, $den2)); /* z_inv = den1*den2*T */

        $ix = self::fe_mul($h->X, $sqrtm1); /* ix = X*sqrt(-1) */
        $iy = self::fe_mul($h->Y, $sqrtm1); /* iy = Y*sqrt(-1) */
        $eden = self::fe_mul($den1, $invsqrtamd);

        $t_z_inv =  self::fe_mul($h->T, $z_inv); /* t_z_inv = T*z_inv */
        $rotate = self::fe_isnegative($t_z_inv);

        $x_ = self::fe_copy($h->X);
        $y_ = self::fe_copy($h->Y);
        $den_inv = self::fe_copy($den2);

        $x_ = self::fe_cmov($x_, $iy, $rotate);
        $y_ = self::fe_cmov($y_, $ix, $rotate);
        $den_inv = self::fe_cmov($den_inv, $eden, $rotate);

        $x_z_inv = self::fe_mul($x_, $z_inv);
        $y_ = self::fe_cneg($y_, self::fe_isnegative($x_z_inv));


        // fe25519_sub(s_, h->Z, y_);
        // fe25519_mul(s_, den_inv, s_);
        // fe25519_abs(s_, s_);
        // fe25519_tobytes(s, s_);
        return self::fe_tobytes(
            self::fe_abs(
                self::fe_mul(
                    $den_inv,
                    self::fe_sub($h->Z, $y_)
                )
            )
        );
    }

    /**
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $t
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
     *
     * @throws SodiumException
     */
    public static function ristretto255_elligator(ParagonIE_Sodium_Core_Curve25519_Fe $t)
    {
        $sqrtm1   = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1);
        $onemsqd  = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$onemsqd);
        $d        = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d);
        $sqdmone  = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqdmone);
        $sqrtadm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtadm1);

        $one = self::fe_1();
        $r   = self::fe_mul($sqrtm1, self::fe_sq($t));         /* r = sqrt(-1)*t^2 */
        $u   = self::fe_mul(self::fe_add($r, $one), $onemsqd); /* u = (r+1)*(1-d^2) */
        $c   = self::fe_neg(self::fe_1());                     /* c = -1 */
        $rpd = self::fe_add($r, $d);                           /* rpd = r+d */

        $v = self::fe_mul(
            self::fe_sub(
                $c,
                self::fe_mul($r, $d)
            ),
            $rpd
        ); /* v = (c-r*d)*(r+d) */

        $result = self::ristretto255_sqrt_ratio_m1($u, $v);
        $s = $result['x'];
        $wasnt_square = 1 - $result['nonsquare'];

        $s_prime = self::fe_neg(
            self::fe_abs(
                self::fe_mul($s, $t)
            )
        ); /* s_prime = -|s*t| */
        $s = self::fe_cmov($s, $s_prime, $wasnt_square);
        $c = self::fe_cmov($c, $r, $wasnt_square);

        // fe25519_sub(n, r, one);            /* n = r-1 */
        // fe25519_mul(n, n, c);              /* n = c*(r-1) */
        // fe25519_mul(n, n, ed25519_sqdmone); /* n = c*(r-1)*(d-1)^2 */
        // fe25519_sub(n, n, v);              /* n =  c*(r-1)*(d-1)^2-v */
        $n = self::fe_sub(
            self::fe_mul(
                self::fe_mul(
                    self::fe_sub($r, $one),
                    $c
                ),
                $sqdmone
            ),
            $v
        ); /* n =  c*(r-1)*(d-1)^2-v */

        $w0 = self::fe_mul(
            self::fe_add($s, $s),
            $v
        ); /* w0 = 2s*v */

        $w1 = self::fe_mul($n, $sqrtadm1); /* w1 = n*sqrt(ad-1) */
        $ss = self::fe_sq($s); /* ss = s^2 */
        $w2 = self::fe_sub($one, $ss); /* w2 = 1-s^2 */
        $w3 = self::fe_add($one, $ss); /* w3 = 1+s^2 */

        return new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
            self::fe_mul($w0, $w3),
            self::fe_mul($w2, $w1),
            self::fe_mul($w1, $w3),
            self::fe_mul($w0, $w2)
        );
    }

    /**
     * @param string $h
     * @return string
     * @throws SodiumException
     */
    public static function ristretto255_from_hash($h)
    {
        if (self::strlen($h) !== 64) {
            throw new SodiumException('Hash must be 64 bytes');
        }
        //fe25519_frombytes(r0, h);
        //fe25519_frombytes(r1, h + 32);
        $r0 = self::fe_frombytes(self::substr($h, 0, 32));
        $r1 = self::fe_frombytes(self::substr($h, 32, 32));

        //ristretto255_elligator(&p0, r0);
        //ristretto255_elligator(&p1, r1);
        $p0 = self::ristretto255_elligator($r0);
        $p1 = self::ristretto255_elligator($r1);

        //ge25519_p3_to_cached(&p1_cached, &p1);
        //ge25519_add_cached(&p_p1p1, &p0, &p1_cached);
        $p_p1p1 = self::ge_add(
            $p0,
            self::ge_p3_to_cached($p1)
        );

        //ge25519_p1p1_to_p3(&p, &p_p1p1);
        //ristretto255_p3_tobytes(s, &p);
        return self::ristretto255_p3_tobytes(
            self::ge_p1p1_to_p3($p_p1p1)
        );
    }

    /**
     * @param string $p
     * @return int
     * @throws SodiumException
     */
    public static function is_valid_point($p)
    {
        $result = self::ristretto255_frombytes($p);
        if ($result['res'] !== 0) {
            return 0;
        }
        return 1;
    }

    /**
     * @param string $p
     * @param string $q
     * @return string
     * @throws SodiumException
     */
    public static function ristretto255_add($p, $q)
    {
        $p_res = self::ristretto255_frombytes($p);
        $q_res = self::ristretto255_frombytes($q);
        if ($p_res['res'] !== 0 || $q_res['res'] !== 0) {
            throw new SodiumException('Could not add points');
        }
        $p_p3 = $p_res['h'];
        $q_p3 = $q_res['h'];
        $q_cached = self::ge_p3_to_cached($q_p3);
        $r_p1p1 = self::ge_add($p_p3, $q_cached);
        $r_p3 = self::ge_p1p1_to_p3($r_p1p1);
        return self::ristretto255_p3_tobytes($r_p3);
    }

    /**
     * @param string $p
     * @param string $q
     * @return string
     * @throws SodiumException
     */
    public static function ristretto255_sub($p, $q)
    {
        $p_res = self::ristretto255_frombytes($p);
        $q_res = self::ristretto255_frombytes($q);
        if ($p_res['res'] !== 0 || $q_res['res'] !== 0) {
            throw new SodiumException('Could not add points');
        }
        $p_p3 = $p_res['h'];
        $q_p3 = $q_res['h'];
        $q_cached = self::ge_p3_to_cached($q_p3);
        $r_p1p1 = self::ge_sub($p_p3, $q_cached);
        $r_p3 = self::ge_p1p1_to_p3($r_p1p1);
        return self::ristretto255_p3_tobytes($r_p3);
    }


    /**
     * @param int $hLen
     * @param ?string $ctx
     * @param string $msg
     * @return string
     * @throws SodiumException
     * @psalm-suppress PossiblyInvalidArgument hash API
     */
    protected static function h2c_string_to_hash_sha256($hLen, $ctx, $msg)
    {
        $h = array_fill(0, $hLen, 0);
        $ctx_len = !is_null($ctx) ? self::strlen($ctx) : 0;
        if ($hLen > 0xff) {
            throw new SodiumException('Hash must be less than 256 bytes');
        }

        if ($ctx_len > 0xff) {
            $st = hash_init('sha256');
            self::hash_update($st, "H2C-OVERSIZE-DST-");
            self::hash_update($st, $ctx);
            $ctx = hash_final($st, true);
            $ctx_len = 32;
        }
        $t = array(0, $hLen, 0);
        $ux = str_repeat("\0", 64);
        $st = hash_init('sha256');
        self::hash_update($st, $ux);
        self::hash_update($st, $msg);
        self::hash_update($st, self::intArrayToString($t));
        self::hash_update($st, $ctx);
        self::hash_update($st, self::intToChr($ctx_len));
        $u0 = hash_final($st, true);

        for ($i = 0; $i < $hLen; $i += 64) {
            $ux = self::xorStrings($ux, $u0);
            ++$t[2];
            $st = hash_init('sha256');
            self::hash_update($st, $ux);
            self::hash_update($st, self::intToChr($t[2]));
            self::hash_update($st, $ctx);
            self::hash_update($st, self::intToChr($ctx_len));
            $ux = hash_final($st, true);
            $amount = min($hLen - $i, 64);
            for ($j = 0; $j < $amount; ++$j) {
                $h[$i + $j] = self::chrToInt($ux[$i]);
            }
        }
        return self::intArrayToString(array_slice($h, 0, $hLen));
    }

    /**
     * @param int $hLen
     * @param ?string $ctx
     * @param string $msg
     * @return string
     * @throws SodiumException
     * @psalm-suppress PossiblyInvalidArgument hash API
     */
    protected static function h2c_string_to_hash_sha512($hLen, $ctx, $msg)
    {
        $h = array_fill(0, $hLen, 0);
        $ctx_len = !is_null($ctx) ? self::strlen($ctx) : 0;
        if ($hLen > 0xff) {
            throw new SodiumException('Hash must be less than 256 bytes');
        }

        if ($ctx_len > 0xff) {
            $st = hash_init('sha256');
            self::hash_update($st, "H2C-OVERSIZE-DST-");
            self::hash_update($st, $ctx);
            $ctx = hash_final($st, true);
            $ctx_len = 32;
        }
        $t = array(0, $hLen, 0);
        $ux = str_repeat("\0", 128);
        $st = hash_init('sha512');
        self::hash_update($st, $ux);
        self::hash_update($st, $msg);
        self::hash_update($st, self::intArrayToString($t));
        self::hash_update($st, $ctx);
        self::hash_update($st, self::intToChr($ctx_len));
        $u0 = hash_final($st, true);

        for ($i = 0; $i < $hLen; $i += 128) {
            $ux = self::xorStrings($ux, $u0);
            ++$t[2];
            $st = hash_init('sha512');
            self::hash_update($st, $ux);
            self::hash_update($st, self::intToChr($t[2]));
            self::hash_update($st, $ctx);
            self::hash_update($st, self::intToChr($ctx_len));
            $ux = hash_final($st, true);
            $amount = min($hLen - $i, 128);
            for ($j = 0; $j < $amount; ++$j) {
                $h[$i + $j] = self::chrToInt($ux[$i]);
            }
        }
        return self::intArrayToString(array_slice($h, 0, $hLen));
    }

    /**
     * @param int $hLen
     * @param ?string $ctx
     * @param string $msg
     * @param int $hash_alg
     * @return string
     * @throws SodiumException
     */
    public static function h2c_string_to_hash($hLen, $ctx, $msg, $hash_alg)
    {
        switch ($hash_alg) {
            case self::CORE_H2C_SHA256:
                return self::h2c_string_to_hash_sha256($hLen, $ctx, $msg);
            case self::CORE_H2C_SHA512:
                return self::h2c_string_to_hash_sha512($hLen, $ctx, $msg);
            default:
                throw new SodiumException('Invalid H2C hash algorithm');
        }
    }

    /**
     * @param ?string $ctx
     * @param string $msg
     * @param int $hash_alg
     * @return string
     * @throws SodiumException
     */
    protected static function _string_to_element($ctx, $msg, $hash_alg)
    {
        return self::ristretto255_from_hash(
            self::h2c_string_to_hash(self::crypto_core_ristretto255_HASHBYTES, $ctx, $msg, $hash_alg)
        );
    }

    /**
     * @return string
     * @throws SodiumException
     * @throws Exception
     */
    public static function ristretto255_random()
    {
        return self::ristretto255_from_hash(
            ParagonIE_Sodium_Compat::randombytes_buf(self::crypto_core_ristretto255_HASHBYTES)
        );
    }

    /**
     * @return string
     * @throws SodiumException
     */
    public static function ristretto255_scalar_random()
    {
        return self::scalar_random();
    }

    /**
     * @param string $s
     * @return string
     * @throws SodiumException
     */
    public static function ristretto255_scalar_complement($s)
    {
        return self::scalar_complement($s);
    }


    /**
     * @param string $s
     * @return string
     */
    public static function ristretto255_scalar_invert($s)
    {
        return self::sc25519_invert($s);
    }

    /**
     * @param string $s
     * @return string
     * @throws SodiumException
     */
    public static function ristretto255_scalar_negate($s)
    {
        return self::scalar_negate($s);
    }

    /**
     * @param string $x
     * @param string $y
     * @return string
     */
    public static function ristretto255_scalar_add($x, $y)
    {
        return self::scalar_add($x, $y);
    }

    /**
     * @param string $x
     * @param string $y
     * @return string
     */
    public static function ristretto255_scalar_sub($x, $y)
    {
        return self::scalar_sub($x, $y);
    }

    /**
     * @param string $x
     * @param string $y
     * @return string
     */
    public static function ristretto255_scalar_mul($x, $y)
    {
        return self::sc25519_mul($x, $y);
    }

    /**
     * @param string $ctx
     * @param string $msg
     * @param int $hash_alg
     * @return string
     * @throws SodiumException
     */
    public static function ristretto255_scalar_from_string($ctx, $msg, $hash_alg)
    {
        $h = array_fill(0, 64, 0);
        $h_be = self::stringToIntArray(
            self::h2c_string_to_hash(
                self::HASH_SC_L, $ctx, $msg, $hash_alg
            )
        );

        for ($i = 0; $i < self::HASH_SC_L; ++$i) {
            $h[$i] = $h_be[self::HASH_SC_L - 1 - $i];
        }
        return self::ristretto255_scalar_reduce(self::intArrayToString($h));
    }

    /**
     * @param string $s
     * @return string
     */
    public static function ristretto255_scalar_reduce($s)
    {
        return self::sc_reduce($s);
    }

    /**
     * @param string $n
     * @param string $p
     * @return string
     * @throws SodiumException
     */
    public static function scalarmult_ristretto255($n, $p)
    {
        if (self::strlen($n) !== 32) {
            throw new SodiumException('Scalar must be 32 bytes, ' . self::strlen($p) . ' given.');
        }
        if (self::strlen($p) !== 32) {
            throw new SodiumException('Point must be 32 bytes, ' . self::strlen($p) . ' given.');
        }
        $result = self::ristretto255_frombytes($p);
        if ($result['res'] !== 0) {
            throw new SodiumException('Could not multiply points');
        }
        $P = $result['h'];

        $t = self::stringToIntArray($n);
        $t[31] &= 0x7f;
        $Q = self::ge_scalarmult(self::intArrayToString($t), $P);
        $q = self::ristretto255_p3_tobytes($Q);
        if (ParagonIE_Sodium_Compat::is_zero($q)) {
            throw new SodiumException('An unknown error has occurred');
        }
        return $q;
    }

    /**
     * @param string $n
     * @return string
     * @throws SodiumException
     */
    public static function scalarmult_ristretto255_base($n)
    {
        $t = self::stringToIntArray($n);
        $t[31] &= 0x7f;
        $Q = self::ge_scalarmult_base(self::intArrayToString($t));
        $q = self::ristretto255_p3_tobytes($Q);
        if (ParagonIE_Sodium_Compat::is_zero($q)) {
            throw new SodiumException('An unknown error has occurred');
        }
        return $q;
    }
}
                                                                                                                                    HChaCha20.php                                                                                       0000644                 00000000146 15172703536 0006650 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class HChaCha20 extends \ParagonIE_Sodium_Core_HChaCha20
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                          AEGIS/State256.php                                                                                  0000644                 00000014575 15172703536 0007447 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

if (class_exists('ParagonIE_Sodium_Core_AEGIS_State256', false)) {
    return;
}

if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
    define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
}
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
    define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
}

class ParagonIE_Sodium_Core_AEGIS_State256
{
    /** @var array<int, string> $state */
    protected $state;
    public function __construct()
    {
        $this->state = array_fill(0, 6, '');
    }

    /**
     * @internal Only use this for unit tests!
     * @return string[]
     */
    public function getState()
    {
        return array_values($this->state);
    }

    /**
     * @param array $input
     * @return self
     * @throws SodiumException
     *
     * @internal Only for unit tests
     */
    public static function initForUnitTests(array $input)
    {
        if (count($input) < 6) {
            throw new SodiumException('invalid input');
        }
        $state = new self();
        for ($i = 0; $i < 6; ++$i) {
            $state->state[$i] = $input[$i];
        }
        return $state;
    }

    /**
     * @param string $key
     * @param string $nonce
     * @return self
     */
    public static function init($key, $nonce)
    {
        $state = new self();
        $k0 = ParagonIE_Sodium_Core_Util::substr($key, 0, 16);
        $k1 = ParagonIE_Sodium_Core_Util::substr($key, 16, 16);
        $n0 = ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16);
        $n1 = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 16);

        // S0 = k0 ^ n0
        // S1 = k1 ^ n1
        // S2 = C1
        // S3 = C0
        // S4 = k0 ^ C0
        // S5 = k1 ^ C1
        $k0_n0 = $k0 ^ $n0;
        $k1_n1 = $k1 ^ $n1;
        $state->state[0] = $k0_n0;
        $state->state[1] = $k1_n1;
        $state->state[2] = SODIUM_COMPAT_AEGIS_C1;
        $state->state[3] = SODIUM_COMPAT_AEGIS_C0;
        $state->state[4] = $k0 ^ SODIUM_COMPAT_AEGIS_C0;
        $state->state[5] = $k1 ^ SODIUM_COMPAT_AEGIS_C1;

        // Repeat(4,
        //   Update(k0)
        //   Update(k1)
        //   Update(k0 ^ n0)
        //   Update(k1 ^ n1)
        // )
        for ($i = 0; $i < 4; ++$i) {
            $state->update($k0);
            $state->update($k1);
            $state->update($k0 ^ $n0);
            $state->update($k1 ^ $n1);
        }
        return $state;
    }

    /**
     * @param string $ai
     * @return self
     * @throws SodiumException
     */
    public function absorb($ai)
    {
        if (ParagonIE_Sodium_Core_Util::strlen($ai) !== 16) {
            throw new SodiumException('Input must be an AES block in size');
        }
        return $this->update($ai);
    }

    /**
     * @param string $ci
     * @return string
     * @throws SodiumException
     */
    public function dec($ci)
    {
        if (ParagonIE_Sodium_Core_Util::strlen($ci) !== 16) {
            throw new SodiumException('Input must be an AES block in size');
        }
        // z = S1 ^ S4 ^ S5 ^ (S2 & S3)
        $z = $this->state[1]
            ^ $this->state[4]
            ^ $this->state[5]
            ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
        $xi = $ci ^ $z;
        $this->update($xi);
        return $xi;
    }

    /**
     * @param string $cn
     * @return string
     */
    public function decPartial($cn)
    {
        $len = ParagonIE_Sodium_Core_Util::strlen($cn);
        // z = S1 ^ S4 ^ S5 ^ (S2 & S3)
        $z = $this->state[1]
            ^ $this->state[4]
            ^ $this->state[5]
            ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);

        // t = ZeroPad(cn, 128)
        $t = str_pad($cn, 16, "\0", STR_PAD_RIGHT);

        // out = t ^ z
        $out = $t ^ $z;

        // xn = Truncate(out, |cn|)
        $xn = ParagonIE_Sodium_Core_Util::substr($out, 0, $len);

        // v = ZeroPad(xn, 128)
        $v = str_pad($xn, 16, "\0", STR_PAD_RIGHT);
        // Update(v)
        $this->update($v);

        // return xn
        return $xn;
    }

    /**
     * @param string $xi
     * @return string
     * @throws SodiumException
     */
    public function enc($xi)
    {
        if (ParagonIE_Sodium_Core_Util::strlen($xi) !== 16) {
            throw new SodiumException('Input must be an AES block in size');
        }
        // z = S1 ^ S4 ^ S5 ^ (S2 & S3)
        $z = $this->state[1]
            ^ $this->state[4]
            ^ $this->state[5]
            ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
        $this->update($xi);
        return $xi ^ $z;
    }

    /**
     * @param int $ad_len_bits
     * @param int $msg_len_bits
     * @return string
     */
    public function finalize($ad_len_bits, $msg_len_bits)
    {
        $encoded = ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) .
            ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits);
        $t = $this->state[3] ^ $encoded;

        for ($i = 0; $i < 7; ++$i) {
            $this->update($t);
        }

        return ($this->state[0] ^ $this->state[1] ^ $this->state[2]) .
            ($this->state[3] ^ $this->state[4] ^ $this->state[5]);
    }

    /**
     * @param string $m
     * @return self
     */
    public function update($m)
    {
        /*
            S'0 = AESRound(S5, S0 ^ M)
            S'1 = AESRound(S0, S1)
            S'2 = AESRound(S1, S2)
            S'3 = AESRound(S2, S3)
            S'4 = AESRound(S3, S4)
            S'5 = AESRound(S4, S5)
         */
        list($s_0, $s_1) = ParagonIE_Sodium_Core_AES::doubleRound(
            $this->state[5],$this->state[0] ^ $m,
            $this->state[0], $this->state[1]
        );

        list($s_2, $s_3) = ParagonIE_Sodium_Core_AES::doubleRound(
            $this->state[1], $this->state[2],
            $this->state[2], $this->state[3]
        );
        list($s_4, $s_5) = ParagonIE_Sodium_Core_AES::doubleRound(
            $this->state[3], $this->state[4],
            $this->state[4], $this->state[5]
        );

        /*
            S0  = S'0
            S1  = S'1
            S2  = S'2
            S3  = S'3
            S4  = S'4
            S5  = S'5
         */
        $this->state[0] = $s_0;
        $this->state[1] = $s_1;
        $this->state[2] = $s_2;
        $this->state[3] = $s_3;
        $this->state[4] = $s_4;
        $this->state[5] = $s_5;
        return $this;
    }
}
                                                                                                                                   AEGIS/State128L.php                                                                                 0000644                 00000020052 15172703536 0007544 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

if (class_exists('ParagonIE_Sodium_Core_AEGIS_State128L', false)) {
    return;
}

if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
    define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
}
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
    define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
}

class ParagonIE_Sodium_Core_AEGIS_State128L
{
    /** @var array<int, string> $state */
    protected $state;
    public function __construct()
    {
        $this->state = array_fill(0, 8, '');
    }

    /**
     * @internal Only use this for unit tests!
     * @return string[]
     */
    public function getState()
    {
        return array_values($this->state);
    }

    /**
     * @param array $input
     * @return self
     * @throws SodiumException
     *
     * @internal Only for unit tests
     */
    public static function initForUnitTests(array $input)
    {
        if (count($input) < 8) {
            throw new SodiumException('invalid input');
        }
        $state = new self();
        for ($i = 0; $i < 8; ++$i) {
            $state->state[$i] = $input[$i];
        }
        return $state;
    }

    /**
     * @param string $key
     * @param string $nonce
     * @return self
     */
    public static function init($key, $nonce)
    {
        $state = new self();

        // S0 = key ^ nonce
        $state->state[0] = $key ^ $nonce;
        // S1 = C1
        $state->state[1] = SODIUM_COMPAT_AEGIS_C1;
        // S2 = C0
        $state->state[2] = SODIUM_COMPAT_AEGIS_C0;
        // S3 = C1
        $state->state[3] = SODIUM_COMPAT_AEGIS_C1;
        // S4 = key ^ nonce
        $state->state[4] = $key ^ $nonce;
        // S5 = key ^ C0
        $state->state[5] = $key ^ SODIUM_COMPAT_AEGIS_C0;
        // S6 = key ^ C1
        $state->state[6] = $key ^ SODIUM_COMPAT_AEGIS_C1;
        // S7 = key ^ C0
        $state->state[7] = $key ^ SODIUM_COMPAT_AEGIS_C0;

        // Repeat(10, Update(nonce, key))
        for ($i = 0; $i < 10; ++$i) {
            $state->update($nonce, $key);
        }
        return $state;
    }

    /**
     * @param string $ai
     * @return self
     */
    public function absorb($ai)
    {
        if (ParagonIE_Sodium_Core_Util::strlen($ai) !== 32) {
            throw new SodiumException('Input must be two AES blocks in size');
        }
        $t0 = ParagonIE_Sodium_Core_Util::substr($ai, 0, 16);
        $t1 = ParagonIE_Sodium_Core_Util::substr($ai, 16, 16);
        return $this->update($t0, $t1);
    }


    /**
     * @param string $ci
     * @return string
     * @throws SodiumException
     */
    public function dec($ci)
    {
        if (ParagonIE_Sodium_Core_Util::strlen($ci) !== 32) {
            throw new SodiumException('Input must be two AES blocks in size');
        }

        // z0 = S6 ^ S1 ^ (S2 & S3)
        $z0 = $this->state[6]
            ^ $this->state[1]
            ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
        // z1 = S2 ^ S5 ^ (S6 & S7)
        $z1 = $this->state[2]
            ^ $this->state[5]
            ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);

        // t0, t1 = Split(xi, 128)
        $t0 = ParagonIE_Sodium_Core_Util::substr($ci, 0, 16);
        $t1 = ParagonIE_Sodium_Core_Util::substr($ci, 16, 16);

        // out0 = t0 ^ z0
        // out1 = t1 ^ z1
        $out0 = $t0 ^ $z0;
        $out1 = $t1 ^ $z1;

        // Update(out0, out1)
        // xi = out0 || out1
        $this->update($out0, $out1);
        return $out0 . $out1;
    }

    /**
     * @param string $cn
     * @return string
     */
    public function decPartial($cn)
    {
        $len = ParagonIE_Sodium_Core_Util::strlen($cn);

        // z0 = S6 ^ S1 ^ (S2 & S3)
        $z0 = $this->state[6]
            ^ $this->state[1]
            ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
        // z1 = S2 ^ S5 ^ (S6 & S7)
        $z1 = $this->state[2]
            ^ $this->state[5]
            ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);

        // t0, t1 = Split(ZeroPad(cn, 256), 128)
        $cn = str_pad($cn, 32, "\0", STR_PAD_RIGHT);
        $t0 = ParagonIE_Sodium_Core_Util::substr($cn, 0, 16);
        $t1 = ParagonIE_Sodium_Core_Util::substr($cn, 16, 16);
        // out0 = t0 ^ z0
        // out1 = t1 ^ z1
        $out0 = $t0 ^ $z0;
        $out1 = $t1 ^ $z1;

        // xn = Truncate(out0 || out1, |cn|)
        $xn = ParagonIE_Sodium_Core_Util::substr($out0 . $out1, 0, $len);

        // v0, v1 = Split(ZeroPad(xn, 256), 128)
        $padded = str_pad($xn, 32, "\0", STR_PAD_RIGHT);
        $v0 = ParagonIE_Sodium_Core_Util::substr($padded, 0, 16);
        $v1 = ParagonIE_Sodium_Core_Util::substr($padded, 16, 16);
        // Update(v0, v1)
        $this->update($v0, $v1);

        // return xn
        return $xn;
    }

    /**
     * @param string $xi
     * @return string
     * @throws SodiumException
     */
    public function enc($xi)
    {
        if (ParagonIE_Sodium_Core_Util::strlen($xi) !== 32) {
            throw new SodiumException('Input must be two AES blocks in size');
        }

        // z0 = S6 ^ S1 ^ (S2 & S3)
        $z0 = $this->state[6]
            ^ $this->state[1]
            ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
        // z1 = S2 ^ S5 ^ (S6 & S7)
        $z1 = $this->state[2]
            ^ $this->state[5]
            ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);

        // t0, t1 = Split(xi, 128)
        $t0 = ParagonIE_Sodium_Core_Util::substr($xi, 0, 16);
        $t1 = ParagonIE_Sodium_Core_Util::substr($xi, 16, 16);

        // out0 = t0 ^ z0
        // out1 = t1 ^ z1
        $out0 = $t0 ^ $z0;
        $out1 = $t1 ^ $z1;

        // Update(t0, t1)
        // ci = out0 || out1
        $this->update($t0, $t1);

        // return ci
        return $out0 . $out1;
    }

    /**
     * @param int $ad_len_bits
     * @param int $msg_len_bits
     * @return string
     */
    public function finalize($ad_len_bits, $msg_len_bits)
    {
        $encoded = ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) .
            ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits);
        $t = $this->state[2] ^ $encoded;
        for ($i = 0; $i < 7; ++$i) {
            $this->update($t, $t);
        }
        return ($this->state[0] ^ $this->state[1] ^ $this->state[2] ^ $this->state[3]) .
            ($this->state[4] ^ $this->state[5] ^ $this->state[6] ^ $this->state[7]);
    }

    /**
     * @param string $m0
     * @param string $m1
     * @return self
     */
    public function update($m0, $m1)
    {
        /*
           S'0 = AESRound(S7, S0 ^ M0)
           S'1 = AESRound(S0, S1)
           S'2 = AESRound(S1, S2)
           S'3 = AESRound(S2, S3)
           S'4 = AESRound(S3, S4 ^ M1)
           S'5 = AESRound(S4, S5)
           S'6 = AESRound(S5, S6)
           S'7 = AESRound(S6, S7)
         */
        list($s_0, $s_1) = ParagonIE_Sodium_Core_AES::doubleRound(
            $this->state[7], $this->state[0] ^ $m0,
            $this->state[0], $this->state[1]
        );

        list($s_2, $s_3) = ParagonIE_Sodium_Core_AES::doubleRound(
            $this->state[1], $this->state[2],
            $this->state[2], $this->state[3]
        );

        list($s_4, $s_5) = ParagonIE_Sodium_Core_AES::doubleRound(
            $this->state[3], $this->state[4] ^ $m1,
            $this->state[4], $this->state[5]
        );
        list($s_6, $s_7) = ParagonIE_Sodium_Core_AES::doubleRound(
            $this->state[5], $this->state[6],
            $this->state[6], $this->state[7]
        );

        /*
           S0  = S'0
           S1  = S'1
           S2  = S'2
           S3  = S'3
           S4  = S'4
           S5  = S'5
           S6  = S'6
           S7  = S'7
         */
        $this->state[0] = $s_0;
        $this->state[1] = $s_1;
        $this->state[2] = $s_2;
        $this->state[3] = $s_3;
        $this->state[4] = $s_4;
        $this->state[5] = $s_5;
        $this->state[6] = $s_6;
        $this->state[7] = $s_7;
        return $this;
    }
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      AEGIS128L.php                                                                                       0000644                 00000007124 15172703536 0006471 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
    define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
}
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
    define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
}

class ParagonIE_Sodium_Core_AEGIS128L extends ParagonIE_Sodium_Core_AES
{
    /**
     * @param string $ct
     * @param string $tag
     * @param string $ad
     * @param string $key
     * @param string $nonce
     * @return string
     * @throws SodiumException
     */
    public static function decrypt($ct, $tag, $ad, $key, $nonce)
    {
        $state = self::init($key, $nonce);
        $ad_blocks = (self::strlen($ad) + 31) >> 5;
        for ($i = 0; $i < $ad_blocks; ++$i) {
            $ai = self::substr($ad, $i << 5, 32);
            if (self::strlen($ai) < 32) {
                $ai = str_pad($ai, 32, "\0", STR_PAD_RIGHT);
            }
            $state->absorb($ai);
        }

        $msg = '';
        $cn = self::strlen($ct) & 31;
        $ct_blocks = self::strlen($ct) >> 5;
        for ($i = 0; $i < $ct_blocks; ++$i) {
            $msg .= $state->dec(self::substr($ct, $i << 5, 32));
        }
        if ($cn) {
            $start = $ct_blocks << 5;
            $msg .= $state->decPartial(self::substr($ct, $start, $cn));
        }
        $expected_tag = $state->finalize(
            self::strlen($ad) << 3,
            self::strlen($msg) << 3
        );
        if (!self::hashEquals($expected_tag, $tag)) {
            try {
                // The RFC says to erase msg, so we shall try:
                ParagonIE_Sodium_Compat::memzero($msg);
            } catch (SodiumException $ex) {
                // Do nothing if we cannot memzero
            }
            throw new SodiumException('verification failed');
        }
        return $msg;
    }

    /**
     * @param string $msg
     * @param string $ad
     * @param string $key
     * @param string $nonce
     * @return array
     *
     * @throws SodiumException
     */
    public static function encrypt($msg, $ad, $key, $nonce)
    {
        $state = self::init($key, $nonce);
        // ad_blocks = Split(ZeroPad(ad, 256), 256)
        // for ai in ad_blocks:
        //     Absorb(ai)
        $ad_len = self::strlen($ad);
        $msg_len = self::strlen($msg);
        $ad_blocks = ($ad_len + 31) >> 5;
        for ($i = 0; $i < $ad_blocks; ++$i) {
            $ai = self::substr($ad, $i << 5, 32);
            if (self::strlen($ai) < 32) {
                $ai = str_pad($ai, 32, "\0", STR_PAD_RIGHT);
            }
            $state->absorb($ai);
        }

        // msg_blocks = Split(ZeroPad(msg, 256), 256)
        // for xi in msg_blocks:
        //     ct = ct || Enc(xi)
        $ct = '';
        $msg_blocks = ($msg_len + 31) >> 5;
        for ($i = 0; $i < $msg_blocks; ++$i) {
            $xi = self::substr($msg, $i << 5, 32);
            if (self::strlen($xi) < 32) {
                $xi = str_pad($xi, 32, "\0", STR_PAD_RIGHT);
            }
            $ct .= $state->enc($xi);
        }
        // tag = Finalize(|ad|, |msg|)
        // ct = Truncate(ct, |msg|)
        $tag = $state->finalize(
            $ad_len << 3,
            $msg_len << 3
        );
        // return ct and tag
        return array(
            self::substr($ct, 0, $msg_len),
            $tag
        );
    }

    /**
     * @param string $key
     * @param string $nonce
     * @return ParagonIE_Sodium_Core_AEGIS_State128L
     */
    public static function init($key, $nonce)
    {
        return ParagonIE_Sodium_Core_AEGIS_State128L::init($key, $nonce);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                            SipHash.php                                                                                         0000644                 00000000142 15172703536 0006622 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class SipHash extends \ParagonIE_Sodium_Core_SipHash
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                              Curve25519.php                                                                                      0000644                 00000000150 15172703536 0006754 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class Curve25519 extends \ParagonIE_Sodium_Core_Curve25519
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                        X25519.php                                                                                          0000644                 00000000140 15172703537 0006077 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class X25519 extends \ParagonIE_Sodium_Core_X25519
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                                HSalsa20.php                                                                                        0000644                 00000000144 15172703537 0006603 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class HSalsa20 extends \ParagonIE_Sodium_Core_HSalsa20
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                            Curve25519/Fe.php                                                                                   0000644                 00000000156 15172703537 0007315 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core\Curve25519;

class Fe extends \ParagonIE_Sodium_Core_Curve25519_Fe
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                  Curve25519/Ge/Precomp.php                                                                           0000644                 00000000176 15172703537 0010725 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;

class Precomp extends \ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
{

}
                                                                                                                                                                                                                                                                                                                                                                                                  Curve25519/Ge/P1p1.php                                                                              0000644                 00000000170 15172703537 0010033 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;

class P1p1 extends \ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
{

}
                                                                                                                                                                                                                                                                                                                                                                                                        Curve25519/Ge/P2.php                                                                                0000644                 00000000164 15172703537 0007576 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;

class P2 extends \ParagonIE_Sodium_Core_Curve25519_Ge_P2
{

}
                                                                                                                                                                                                                                                                                                                                                                                                            Curve25519/Ge/P3.php                                                                                0000644                 00000000164 15172703537 0007577 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;

class P3 extends \ParagonIE_Sodium_Core_Curve25519_Ge_P3
{

}
                                                                                                                                                                                                                                                                                                                                                                                                            Curve25519/Ge/Cached.php                                                                            0000644                 00000000174 15172703537 0010465 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;

class Cached extends \ParagonIE_Sodium_Core_Curve25519_Ge_Cached
{

}
                                                                                                                                                                                                                                                                                                                                                                                                    Curve25519/H.php                                                                                    0000644                 00000000154 15172703537 0007150 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core\Curve25519;

class H extends \ParagonIE_Sodium_Core_Curve25519_H
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                    Curve25519/README.md                                                                                0000644                 00000000332 15172703537 0007525 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       # Curve25519 Data Structures

These are PHP implementation of the [structs used in the ref10 curve25519 code](https://github.com/jedisct1/libsodium/blob/master/src/libsodium/include/sodium/private/curve25519_ref10.h).
                                                                                                                                                                                                                                                                                                      Poly1305/State.php                                                                                  0000644                 00000000160 15172703537 0007600 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core\Poly1305;

class State extends \ParagonIE_Sodium_Core_Poly1305_State
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                Salsa20.php                                                                                         0000644                 00000000142 15172703537 0006471 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class Salsa20 extends \ParagonIE_Sodium_Core_Salsa20
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                              ChaCha20.php                                                                                        0000644                 00000000144 15172703537 0006537 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class ChaCha20 extends \ParagonIE_Sodium_Core_ChaCha20
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                            Poly1305.php                                                                                        0000644                 00000000144 15172703540 0006514 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class Poly1305 extends \ParagonIE_Sodium_Core_Poly1305
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                            error_log                                                                                           0000644                 00000011253 15172703540 0006467 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       [21-Apr-2026 23:15:56 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/ChaCha20.php:10
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/ChaCha20.php on line 10
[21-Apr-2026 23:15:57 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_AES" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/AEGIS128L.php:10
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/AEGIS128L.php on line 10
[21-Apr-2026 23:15:57 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_ChaCha20" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/HChaCha20.php:10
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/HChaCha20.php on line 10
[21-Apr-2026 23:15:57 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_Salsa20" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/HSalsa20.php:10
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/HSalsa20.php on line 10
[21-Apr-2026 23:15:57 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/BLAKE2b.php:12
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/BLAKE2b.php on line 12
[21-Apr-2026 23:15:57 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/AES.php:14
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/AES.php on line 14
[21-Apr-2026 23:15:57 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519_H" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/Curve25519.php:16
Stack trace:
#0 /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/Ed25519.php(7): require_once()
#1 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/Curve25519.php on line 16
[21-Apr-2026 23:15:58 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_AES" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/AEGIS256.php:10
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/AEGIS256.php on line 10
[21-Apr-2026 23:15:59 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/Salsa20.php:10
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/Salsa20.php on line 10
[21-Apr-2026 23:15:59 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_Ed25519" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/Ristretto255.php:6
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/Ristretto255.php on line 6
[21-Apr-2026 23:16:01 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/SipHash.php:12
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/SipHash.php on line 12
[21-Apr-2026 23:16:01 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519_H" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/Curve25519.php:16
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/Curve25519.php on line 16
[21-Apr-2026 23:16:03 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/X25519.php:10
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/X25519.php on line 10
[21-Apr-2026 23:16:04 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_HSalsa20" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/XSalsa20.php:10
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/XSalsa20.php on line 10
[21-Apr-2026 23:16:06 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/Poly1305.php:10
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/Poly1305.php on line 10
                                                                                                                                                                                                                                                                                                                                                     AES.php                                                                                             0000644                 00000037015 15172703540 0005677 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

if (class_exists('ParagonIE_Sodium_Core_AES', false)) {
    return;
}

/**
 * Bitsliced implementation of the AES block cipher.
 *
 * Based on the implementation provided by BearSSL.
 *
 * @internal This should only be used by sodium_compat
 */
class ParagonIE_Sodium_Core_AES extends ParagonIE_Sodium_Core_Util
{
    /**
     * @var int[] AES round constants
     */
    private static $Rcon = array(
        0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
    );

    /**
     * Mutates the values of $q!
     *
     * @param ParagonIE_Sodium_Core_AES_Block $q
     * @return void
     */
    public static function sbox(ParagonIE_Sodium_Core_AES_Block $q)
    {
        /**
         * @var int $x0
         * @var int $x1
         * @var int $x2
         * @var int $x3
         * @var int $x4
         * @var int $x5
         * @var int $x6
         * @var int $x7
         */
        $x0 = $q[7] & self::U32_MAX;
        $x1 = $q[6] & self::U32_MAX;
        $x2 = $q[5] & self::U32_MAX;
        $x3 = $q[4] & self::U32_MAX;
        $x4 = $q[3] & self::U32_MAX;
        $x5 = $q[2] & self::U32_MAX;
        $x6 = $q[1] & self::U32_MAX;
        $x7 = $q[0] & self::U32_MAX;

        $y14 = $x3 ^ $x5;
        $y13 = $x0 ^ $x6;
        $y9 = $x0 ^ $x3;
        $y8 = $x0 ^ $x5;
        $t0 = $x1 ^ $x2;
        $y1 = $t0 ^ $x7;
        $y4 = $y1 ^ $x3;
        $y12 = $y13 ^ $y14;
        $y2 = $y1 ^ $x0;
        $y5 = $y1 ^ $x6;
        $y3 = $y5 ^ $y8;
        $t1 = $x4 ^ $y12;
        $y15 = $t1 ^ $x5;
        $y20 = $t1 ^ $x1;
        $y6 = $y15 ^ $x7;
        $y10 = $y15 ^ $t0;
        $y11 = $y20 ^ $y9;
        $y7 = $x7 ^ $y11;
        $y17 = $y10 ^ $y11;
        $y19 = $y10 ^ $y8;
        $y16 = $t0 ^ $y11;
        $y21 = $y13 ^ $y16;
        $y18 = $x0 ^ $y16;

        /*
         * Non-linear section.
         */
        $t2 = $y12 & $y15;
        $t3 = $y3 & $y6;
        $t4 = $t3 ^ $t2;
        $t5 = $y4 & $x7;
        $t6 = $t5 ^ $t2;
        $t7 = $y13 & $y16;
        $t8 = $y5 & $y1;
        $t9 = $t8 ^ $t7;
        $t10 = $y2 & $y7;
        $t11 = $t10 ^ $t7;
        $t12 = $y9 & $y11;
        $t13 = $y14 & $y17;
        $t14 = $t13 ^ $t12;
        $t15 = $y8 & $y10;
        $t16 = $t15 ^ $t12;
        $t17 = $t4 ^ $t14;
        $t18 = $t6 ^ $t16;
        $t19 = $t9 ^ $t14;
        $t20 = $t11 ^ $t16;
        $t21 = $t17 ^ $y20;
        $t22 = $t18 ^ $y19;
        $t23 = $t19 ^ $y21;
        $t24 = $t20 ^ $y18;

        $t25 = $t21 ^ $t22;
        $t26 = $t21 & $t23;
        $t27 = $t24 ^ $t26;
        $t28 = $t25 & $t27;
        $t29 = $t28 ^ $t22;
        $t30 = $t23 ^ $t24;
        $t31 = $t22 ^ $t26;
        $t32 = $t31 & $t30;
        $t33 = $t32 ^ $t24;
        $t34 = $t23 ^ $t33;
        $t35 = $t27 ^ $t33;
        $t36 = $t24 & $t35;
        $t37 = $t36 ^ $t34;
        $t38 = $t27 ^ $t36;
        $t39 = $t29 & $t38;
        $t40 = $t25 ^ $t39;

        $t41 = $t40 ^ $t37;
        $t42 = $t29 ^ $t33;
        $t43 = $t29 ^ $t40;
        $t44 = $t33 ^ $t37;
        $t45 = $t42 ^ $t41;
        $z0 = $t44 & $y15;
        $z1 = $t37 & $y6;
        $z2 = $t33 & $x7;
        $z3 = $t43 & $y16;
        $z4 = $t40 & $y1;
        $z5 = $t29 & $y7;
        $z6 = $t42 & $y11;
        $z7 = $t45 & $y17;
        $z8 = $t41 & $y10;
        $z9 = $t44 & $y12;
        $z10 = $t37 & $y3;
        $z11 = $t33 & $y4;
        $z12 = $t43 & $y13;
        $z13 = $t40 & $y5;
        $z14 = $t29 & $y2;
        $z15 = $t42 & $y9;
        $z16 = $t45 & $y14;
        $z17 = $t41 & $y8;

        /*
         * Bottom linear transformation.
         */
        $t46 = $z15 ^ $z16;
        $t47 = $z10 ^ $z11;
        $t48 = $z5 ^ $z13;
        $t49 = $z9 ^ $z10;
        $t50 = $z2 ^ $z12;
        $t51 = $z2 ^ $z5;
        $t52 = $z7 ^ $z8;
        $t53 = $z0 ^ $z3;
        $t54 = $z6 ^ $z7;
        $t55 = $z16 ^ $z17;
        $t56 = $z12 ^ $t48;
        $t57 = $t50 ^ $t53;
        $t58 = $z4 ^ $t46;
        $t59 = $z3 ^ $t54;
        $t60 = $t46 ^ $t57;
        $t61 = $z14 ^ $t57;
        $t62 = $t52 ^ $t58;
        $t63 = $t49 ^ $t58;
        $t64 = $z4 ^ $t59;
        $t65 = $t61 ^ $t62;
        $t66 = $z1 ^ $t63;
        $s0 = $t59 ^ $t63;
        $s6 = $t56 ^ ~$t62;
        $s7 = $t48 ^ ~$t60;
        $t67 = $t64 ^ $t65;
        $s3 = $t53 ^ $t66;
        $s4 = $t51 ^ $t66;
        $s5 = $t47 ^ $t65;
        $s1 = $t64 ^ ~$s3;
        $s2 = $t55 ^ ~$t67;

        $q[7] = $s0 & self::U32_MAX;
        $q[6] = $s1 & self::U32_MAX;
        $q[5] = $s2 & self::U32_MAX;
        $q[4] = $s3 & self::U32_MAX;
        $q[3] = $s4 & self::U32_MAX;
        $q[2] = $s5 & self::U32_MAX;
        $q[1] = $s6 & self::U32_MAX;
        $q[0] = $s7 & self::U32_MAX;
    }

    /**
     * Mutates the values of $q!
     *
     * @param ParagonIE_Sodium_Core_AES_Block $q
     * @return void
     */
    public static function invSbox(ParagonIE_Sodium_Core_AES_Block $q)
    {
        self::processInversion($q);
        self::sbox($q);
        self::processInversion($q);
    }

    /**
     * This is some boilerplate code needed to invert an S-box. Rather than repeat the code
     * twice, I moved it to a protected method.
     *
     * Mutates $q
     *
     * @param ParagonIE_Sodium_Core_AES_Block $q
     * @return void
     */
    protected static function processInversion(ParagonIE_Sodium_Core_AES_Block $q)
    {
        $q0 = (~$q[0]) & self::U32_MAX;
        $q1 = (~$q[1]) & self::U32_MAX;
        $q2 = $q[2] & self::U32_MAX;
        $q3 = $q[3] & self::U32_MAX;
        $q4 = $q[4] & self::U32_MAX;
        $q5 = (~$q[5])  & self::U32_MAX;
        $q6 = (~$q[6])  & self::U32_MAX;
        $q7 = $q[7] & self::U32_MAX;
        $q[7] = ($q1 ^ $q4 ^ $q6) & self::U32_MAX;
        $q[6] = ($q0 ^ $q3 ^ $q5) & self::U32_MAX;
        $q[5] = ($q7 ^ $q2 ^ $q4) & self::U32_MAX;
        $q[4] = ($q6 ^ $q1 ^ $q3) & self::U32_MAX;
        $q[3] = ($q5 ^ $q0 ^ $q2) & self::U32_MAX;
        $q[2] = ($q4 ^ $q7 ^ $q1) & self::U32_MAX;
        $q[1] = ($q3 ^ $q6 ^ $q0) & self::U32_MAX;
        $q[0] = ($q2 ^ $q5 ^ $q7) & self::U32_MAX;
    }

    /**
     * @param int $x
     * @return int
     */
    public static function subWord($x)
    {
        $q = ParagonIE_Sodium_Core_AES_Block::fromArray(
            array($x, $x, $x, $x, $x, $x, $x, $x)
        );
        $q->orthogonalize();
        self::sbox($q);
        $q->orthogonalize();
        return $q[0] & self::U32_MAX;
    }

    /**
     * Calculate the key schedule from a given random key
     *
     * @param string $key
     * @return ParagonIE_Sodium_Core_AES_KeySchedule
     * @throws SodiumException
     */
    public static function keySchedule($key)
    {
        $key_len = self::strlen($key);
        switch ($key_len) {
            case 16:
                $num_rounds = 10;
                break;
            case 24:
                $num_rounds = 12;
                break;
            case 32:
                $num_rounds = 14;
                break;
            default:
                throw new SodiumException('Invalid key length: ' . $key_len);
        }
        $skey = array();
        $comp_skey = array();
        $nk = $key_len >> 2;
        $nkf = ($num_rounds + 1) << 2;
        $tmp = 0;

        for ($i = 0; $i < $nk; ++$i) {
            $tmp = self::load_4(self::substr($key, $i << 2, 4));
            $skey[($i << 1)] = $tmp;
            $skey[($i << 1) + 1] = $tmp;
        }

        for ($i = $nk, $j = 0, $k = 0; $i < $nkf; ++$i) {
            if ($j === 0) {
                $tmp = (($tmp & 0xff) << 24) | ($tmp >> 8);
                $tmp = (self::subWord($tmp) ^ self::$Rcon[$k]) & self::U32_MAX;
            } elseif ($nk > 6 && $j === 4) {
                $tmp = self::subWord($tmp);
            }
            $tmp ^= $skey[($i - $nk) << 1];
            $skey[($i << 1)] = $tmp & self::U32_MAX;
            $skey[($i << 1) + 1] = $tmp & self::U32_MAX;
            if (++$j === $nk) {
                /** @psalm-suppress LoopInvalidation */
                $j = 0;
                ++$k;
            }
        }
        for ($i = 0; $i < $nkf; $i += 4) {
            $q = ParagonIE_Sodium_Core_AES_Block::fromArray(
                array_slice($skey, $i << 1, 8)
            );
            $q->orthogonalize();
            // We have to overwrite $skey since we're not using C pointers like BearSSL did
            for ($j = 0; $j < 8; ++$j) {
                $skey[($i << 1) + $j] = $q[$j];
            }
        }
        for ($i = 0, $j = 0; $i < $nkf; ++$i, $j += 2) {
            $comp_skey[$i] = ($skey[$j] & 0x55555555)
                | ($skey[$j + 1] & 0xAAAAAAAA);
        }
        return new ParagonIE_Sodium_Core_AES_KeySchedule($comp_skey, $num_rounds);
    }

    /**
     * Mutates $q
     *
     * @param ParagonIE_Sodium_Core_AES_KeySchedule $skey
     * @param ParagonIE_Sodium_Core_AES_Block $q
     * @param int $offset
     * @return void
     */
    public static function addRoundKey(
        ParagonIE_Sodium_Core_AES_Block $q,
        ParagonIE_Sodium_Core_AES_KeySchedule $skey,
        $offset = 0
    ) {
        $block = $skey->getRoundKey($offset);
        for ($j = 0; $j < 8; ++$j) {
            $q[$j] = ($q[$j] ^ $block[$j]) & ParagonIE_Sodium_Core_Util::U32_MAX;
        }
    }

    /**
     * This mainly exists for testing, as we need the round key features for AEGIS.
     *
     * @param string $message
     * @param string $key
     * @return string
     * @throws SodiumException
     */
    public static function decryptBlockECB($message, $key)
    {
        if (self::strlen($message) !== 16) {
            throw new SodiumException('decryptBlockECB() expects a 16 byte message');
        }
        $skey = self::keySchedule($key)->expand();
        $q = ParagonIE_Sodium_Core_AES_Block::init();
        $q[0] = self::load_4(self::substr($message, 0, 4));
        $q[2] = self::load_4(self::substr($message, 4, 4));
        $q[4] = self::load_4(self::substr($message, 8, 4));
        $q[6] = self::load_4(self::substr($message, 12, 4));

        $q->orthogonalize();
        self::bitsliceDecryptBlock($skey, $q);
        $q->orthogonalize();

        return self::store32_le($q[0]) .
            self::store32_le($q[2]) .
            self::store32_le($q[4]) .
            self::store32_le($q[6]);
    }

    /**
     * This mainly exists for testing, as we need the round key features for AEGIS.
     *
     * @param string $message
     * @param string $key
     * @return string
     * @throws SodiumException
     */
    public static function encryptBlockECB($message, $key)
    {
        if (self::strlen($message) !== 16) {
            throw new SodiumException('encryptBlockECB() expects a 16 byte message');
        }
        $comp_skey = self::keySchedule($key);
        $skey = $comp_skey->expand();
        $q = ParagonIE_Sodium_Core_AES_Block::init();
        $q[0] = self::load_4(self::substr($message, 0, 4));
        $q[2] = self::load_4(self::substr($message, 4, 4));
        $q[4] = self::load_4(self::substr($message, 8, 4));
        $q[6] = self::load_4(self::substr($message, 12, 4));

        $q->orthogonalize();
        self::bitsliceEncryptBlock($skey, $q);
        $q->orthogonalize();

        return self::store32_le($q[0]) .
            self::store32_le($q[2]) .
            self::store32_le($q[4]) .
            self::store32_le($q[6]);
    }

    /**
     * Mutates $q
     *
     * @param ParagonIE_Sodium_Core_AES_Expanded $skey
     * @param ParagonIE_Sodium_Core_AES_Block $q
     * @return void
     */
    public static function bitsliceEncryptBlock(
        ParagonIE_Sodium_Core_AES_Expanded $skey,
        ParagonIE_Sodium_Core_AES_Block $q
    ) {
        self::addRoundKey($q, $skey);
        for ($u = 1; $u < $skey->getNumRounds(); ++$u) {
            self::sbox($q);
            $q->shiftRows();
            $q->mixColumns();
            self::addRoundKey($q, $skey, ($u << 3));
        }
        self::sbox($q);
        $q->shiftRows();
        self::addRoundKey($q, $skey, ($skey->getNumRounds() << 3));
    }

    /**
     * @param string $x
     * @param string $y
     * @return string
     */
    public static function aesRound($x, $y)
    {
        $q = ParagonIE_Sodium_Core_AES_Block::init();
        $q[0] = self::load_4(self::substr($x, 0, 4));
        $q[2] = self::load_4(self::substr($x, 4, 4));
        $q[4] = self::load_4(self::substr($x, 8, 4));
        $q[6] = self::load_4(self::substr($x, 12, 4));

        $rk = ParagonIE_Sodium_Core_AES_Block::init();
        $rk[0] = $rk[1] = self::load_4(self::substr($y, 0, 4));
        $rk[2] = $rk[3] = self::load_4(self::substr($y, 4, 4));
        $rk[4] = $rk[5] = self::load_4(self::substr($y, 8, 4));
        $rk[6] = $rk[7] = self::load_4(self::substr($y, 12, 4));

        $q->orthogonalize();
        self::sbox($q);
        $q->shiftRows();
        $q->mixColumns();
        $q->orthogonalize();
        // add round key without key schedule:
        for ($i = 0; $i < 8; ++$i) {
            $q[$i] ^= $rk[$i];
        }
        return self::store32_le($q[0]) .
            self::store32_le($q[2]) .
            self::store32_le($q[4]) .
            self::store32_le($q[6]);
    }

    /**
     * Process two AES blocks in one shot.
     *
     * @param string $b0  First AES block
     * @param string $rk0 First round key
     * @param string $b1  Second AES block
     * @param string $rk1 Second round key
     * @return string[]
     */
    public static function doubleRound($b0, $rk0, $b1, $rk1)
    {
        $q = ParagonIE_Sodium_Core_AES_Block::init();
        // First block
        $q[0] = self::load_4(self::substr($b0, 0, 4));
        $q[2] = self::load_4(self::substr($b0, 4, 4));
        $q[4] = self::load_4(self::substr($b0, 8, 4));
        $q[6] = self::load_4(self::substr($b0, 12, 4));
        // Second block
        $q[1] = self::load_4(self::substr($b1, 0, 4));
        $q[3] = self::load_4(self::substr($b1, 4, 4));
        $q[5] = self::load_4(self::substr($b1, 8, 4));
        $q[7] = self::load_4(self::substr($b1, 12, 4));;

        $rk = ParagonIE_Sodium_Core_AES_Block::init();
        // First round key
        $rk[0] = self::load_4(self::substr($rk0, 0, 4));
        $rk[2] = self::load_4(self::substr($rk0, 4, 4));
        $rk[4] = self::load_4(self::substr($rk0, 8, 4));
        $rk[6] = self::load_4(self::substr($rk0, 12, 4));
        // Second round key
        $rk[1] = self::load_4(self::substr($rk1, 0, 4));
        $rk[3] = self::load_4(self::substr($rk1, 4, 4));
        $rk[5] = self::load_4(self::substr($rk1, 8, 4));
        $rk[7] = self::load_4(self::substr($rk1, 12, 4));

        $q->orthogonalize();
        self::sbox($q);
        $q->shiftRows();
        $q->mixColumns();
        $q->orthogonalize();
        // add round key without key schedule:
        for ($i = 0; $i < 8; ++$i) {
            $q[$i] ^= $rk[$i];
        }
        return array(
            self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]),
            self::store32_le($q[1]) . self::store32_le($q[3]) . self::store32_le($q[5]) . self::store32_le($q[7]),
        );
    }

    /**
     * @param ParagonIE_Sodium_Core_AES_Expanded $skey
     * @param ParagonIE_Sodium_Core_AES_Block $q
     * @return void
     */
    public static function bitsliceDecryptBlock(
        ParagonIE_Sodium_Core_AES_Expanded $skey,
        ParagonIE_Sodium_Core_AES_Block $q
    ) {
        self::addRoundKey($q, $skey, ($skey->getNumRounds() << 3));
        for ($u = $skey->getNumRounds() - 1; $u > 0; --$u) {
            $q->inverseShiftRows();
            self::invSbox($q);
            self::addRoundKey($q, $skey, ($u << 3));
            $q->inverseMixColumns();
        }
        $q->inverseShiftRows();
        self::invSbox($q);
        self::addRoundKey($q, $skey, ($u << 3));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   ChaCha20/IetfCtx.php                                                                                0000644                 00000000164 15172703540 0010101 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core\ChaCha20;

class IetfCtx extends \ParagonIE_Sodium_Core_ChaCha20_IetfCtx
{

}
                                                                                                                                                                                                                                                                                                                                                                                                            ChaCha20/error_log                                                                                  0000644                 00000001214 15172703540 0007734 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       [21-Apr-2026 23:16:04 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/ChaCha20/Ctx.php:10
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/ChaCha20/Ctx.php on line 10
[21-Apr-2026 23:16:05 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_ChaCha20_Ctx" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/ChaCha20/IetfCtx.php:10
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/ChaCha20/IetfCtx.php on line 10
                                                                                                                                                                                                                                                                                                                                                                                    ChaCha20/Ctx.php                                                                                    0000644                 00000000154 15172703540 0007270 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core\ChaCha20;

class Ctx extends \ParagonIE_Sodium_Core_ChaCha20_Ctx
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                    XSalsa20.php                                                                                        0000644                 00000002533 15172703540 0006621 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

if (class_exists('ParagonIE_Sodium_Core_XSalsa20', false)) {
    return;
}

/**
 * Class ParagonIE_Sodium_Core_XSalsa20
 */
abstract class ParagonIE_Sodium_Core_XSalsa20 extends ParagonIE_Sodium_Core_HSalsa20
{
    /**
     * Expand a key and nonce into an xsalsa20 keystream.
     *
     * @internal You should not use this directly from another application
     *
     * @param int $len
     * @param string $nonce
     * @param string $key
     * @return string
     * @throws SodiumException
     * @throws TypeError
     */
    public static function xsalsa20($len, $nonce, $key)
    {
        $ret = self::salsa20(
            $len,
            self::substr($nonce, 16, 8),
            self::hsalsa20($nonce, $key)
        );
        return $ret;
    }

    /**
     * Encrypt a string with XSalsa20. Doesn't provide integrity.
     *
     * @internal You should not use this directly from another application
     *
     * @param string $message
     * @param string $nonce
     * @param string $key
     * @return string
     * @throws SodiumException
     * @throws TypeError
     */
    public static function xsalsa20_xor($message, $nonce, $key)
    {
        return self::xorStrings(
            $message,
            self::xsalsa20(
                self::strlen($message),
                $nonce,
                $key
            )
        );
    }
}
                                                                                                                                                                     Ed25519.php                                                                                         0000644                 00000000142 15172703540 0006214 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class Ed25519 extends \ParagonIE_Sodium_Core_Ed25519
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                              BLAKE2b.php                                                                                         0000644                 00000000142 15172703540 0006320 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class BLAKE2b extends \ParagonIE_Sodium_Core_BLAKE2b
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                              AES/Expanded.php                                                                                    0000644                 00000000460 15172703540 0007421 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

if (class_exists('ParagonIE_Sodium_Core_AES_Expanded', false)) {
    return;
}

/**
 * @internal This should only be used by sodium_compat
 */
class ParagonIE_Sodium_Core_AES_Expanded extends ParagonIE_Sodium_Core_AES_KeySchedule
{
    /** @var bool $expanded */
    protected $expanded = true;
}
                                                                                                                                                                                                                AES/KeySchedule.php                                                                                 0000644                 00000003531 15172703540 0010100 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

if (class_exists('ParagonIE_Sodium_Core_AES_KeySchedule', false)) {
    return;
}

/**
 * @internal This should only be used by sodium_compat
 */
class ParagonIE_Sodium_Core_AES_KeySchedule
{
    /** @var array<int, int> $skey -- has size 120 */
    protected $skey;

    /** @var bool $expanded */
    protected $expanded = false;

    /** @var int $numRounds */
    private $numRounds;

    /**
     * @param array $skey
     * @param int $numRounds
     */
    public function __construct(array $skey, $numRounds = 10)
    {
        $this->skey = $skey;
        $this->numRounds = $numRounds;
    }

    /**
     * Get a value at an arbitrary index. Mostly used for unit testing.
     *
     * @param int $i
     * @return int
     */
    public function get($i)
    {
        return $this->skey[$i];
    }

    /**
     * @return int
     */
    public function getNumRounds()
    {
        return $this->numRounds;
    }

    /**
     * @param int $offset
     * @return ParagonIE_Sodium_Core_AES_Block
     */
    public function getRoundKey($offset)
    {
        return ParagonIE_Sodium_Core_AES_Block::fromArray(
            array_slice($this->skey, $offset, 8)
        );
    }

    /**
     * Return an expanded key schedule
     *
     * @return ParagonIE_Sodium_Core_AES_Expanded
     */
    public function expand()
    {
        $exp = new ParagonIE_Sodium_Core_AES_Expanded(
            array_fill(0, 120, 0),
            $this->numRounds
        );
        $n = ($exp->numRounds + 1) << 2;
        for ($u = 0, $v = 0; $u < $n; ++$u, $v += 2) {
            $x = $y = $this->skey[$u];
            $x &= 0x55555555;
            $exp->skey[$v] = ($x | ($x << 1)) & ParagonIE_Sodium_Core_Util::U32_MAX;
            $y &= 0xAAAAAAAA;
            $exp->skey[$v + 1] = ($y | ($y >> 1)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        }
        return $exp;
    }
}
                                                                                                                                                                       AES/error_log                                                                                       0000644                 00000000511 15172703540 0007072 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       [21-Apr-2026 23:16:08 UTC] PHP Fatal error:  Uncaught Error: Class "ParagonIE_Sodium_Core_AES_KeySchedule" not found in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/AES/Expanded.php:10
Stack trace:
#0 {main}
  thrown in /home/manesbcf/kidvite.shop/wp-includes/sodium_compat/src/Core/AES/Expanded.php on line 10
                                                                                                                                                                                       AES/Block.php                                                                                       0000644                 00000024342 15172703540 0006730 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

if (class_exists('ParagonIE_Sodium_Core_AES_Block', false)) {
    return;
}

/**
 * @internal This should only be used by sodium_compat
 */
class ParagonIE_Sodium_Core_AES_Block extends SplFixedArray
{
    /**
     * @var array<int, int>
     */
    protected $values = array();

    /**
     * @var int
     */
    protected $size;

    /**
     * @param int $size
     */
    public function __construct($size = 8)
    {
        parent::__construct($size);
        $this->size = $size;
        $this->values = array_fill(0, $size, 0);
    }

    /**
     * @return self
     */
    public static function init()
    {
        return new self(8);
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param array<int, int> $array
     * @param bool $save_indexes
     * @return self
     *
     * @psalm-suppress MethodSignatureMismatch
     */
    #[ReturnTypeWillChange]
    public static function fromArray($array, $save_indexes = null)
    {
        $count = count($array);
        if ($save_indexes) {
            $keys = array_keys($array);
        } else {
            $keys = range(0, $count - 1);
        }
        $array = array_values($array);
        /** @var array<int, int> $keys */

        $obj = new ParagonIE_Sodium_Core_AES_Block();
        if ($save_indexes) {
            for ($i = 0; $i < $count; ++$i) {
                $obj->offsetSet($keys[$i], $array[$i]);
            }
        } else {
            for ($i = 0; $i < $count; ++$i) {
                $obj->offsetSet($i, $array[$i]);
            }
        }
        return $obj;
    }


    /**
     * @internal You should not use this directly from another application
     *
     * @param int|null $offset
     * @param int $value
     * @return void
     *
     * @psalm-suppress MethodSignatureMismatch
     * @psalm-suppress MixedArrayOffset
     */
    #[ReturnTypeWillChange]
    public function offsetSet($offset, $value)
    {
        if (!is_int($value)) {
            throw new InvalidArgumentException('Expected an integer');
        }
        if (is_null($offset)) {
            $this->values[] = $value;
        } else {
            $this->values[$offset] = $value;
        }
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param int $offset
     * @return bool
     *
     * @psalm-suppress MethodSignatureMismatch
     * @psalm-suppress MixedArrayOffset
     */
    #[ReturnTypeWillChange]
    public function offsetExists($offset)
    {
        return isset($this->values[$offset]);
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param int $offset
     * @return void
     *
     * @psalm-suppress MethodSignatureMismatch
     * @psalm-suppress MixedArrayOffset
     */
    #[ReturnTypeWillChange]
    public function offsetUnset($offset)
    {
        unset($this->values[$offset]);
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param int $offset
     * @return int
     *
     * @psalm-suppress MethodSignatureMismatch
     * @psalm-suppress MixedArrayOffset
     */
    #[ReturnTypeWillChange]
    public function offsetGet($offset)
    {
        if (!isset($this->values[$offset])) {
            $this->values[$offset] = 0;
        }
        return (int) ($this->values[$offset]);
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @return array
     */
    public function __debugInfo()
    {
        $out = array();
        foreach ($this->values as $v) {
            $out[] = str_pad(dechex($v), 8, '0', STR_PAD_LEFT);
        }
        return array(implode(', ', $out));
        /*
         return array(implode(', ', $this->values));
         */
    }

    /**
     * @param int $cl low bit mask
     * @param int $ch high bit mask
     * @param int $s shift
     * @param int $x index 1
     * @param int $y index 2
     * @return self
     */
    public function swapN($cl, $ch, $s, $x, $y)
    {
        static $u32mask = ParagonIE_Sodium_Core_Util::U32_MAX;
        $a = $this->values[$x] & $u32mask;
        $b = $this->values[$y] & $u32mask;
        // (x) = (a & cl) | ((b & cl) << (s));
        $this->values[$x] = ($a & $cl) | ((($b & $cl) << $s) & $u32mask);
        // (y) = ((a & ch) >> (s)) | (b & ch);
        $this->values[$y] = ((($a & $ch) & $u32mask) >> $s) | ($b & $ch);
        return $this;
    }

    /**
     * @param int $x index 1
     * @param int $y index 2
     * @return self
     */
    public function swap2($x, $y)
    {
        return $this->swapN(0x55555555, 0xAAAAAAAA, 1, $x, $y);
    }

    /**
     * @param int $x index 1
     * @param int $y index 2
     * @return self
     */
    public function swap4($x, $y)
    {
        return $this->swapN(0x33333333, 0xCCCCCCCC, 2, $x, $y);
    }

    /**
     * @param int $x index 1
     * @param int $y index 2
     * @return self
     */
    public function swap8($x, $y)
    {
        return $this->swapN(0x0F0F0F0F, 0xF0F0F0F0, 4, $x, $y);
    }

    /**
     * @return self
     */
    public function orthogonalize()
    {
        return $this
            ->swap2(0, 1)
            ->swap2(2, 3)
            ->swap2(4, 5)
            ->swap2(6, 7)

            ->swap4(0, 2)
            ->swap4(1, 3)
            ->swap4(4, 6)
            ->swap4(5, 7)

            ->swap8(0, 4)
            ->swap8(1, 5)
            ->swap8(2, 6)
            ->swap8(3, 7);
    }

    /**
     * @return self
     */
    public function shiftRows()
    {
        for ($i = 0; $i < 8; ++$i) {
            $x = $this->values[$i] & ParagonIE_Sodium_Core_Util::U32_MAX;
            $this->values[$i] = (
                ($x & 0x000000FF)
                    | (($x & 0x0000FC00) >> 2) | (($x & 0x00000300) << 6)
                    | (($x & 0x00F00000) >> 4) | (($x & 0x000F0000) << 4)
                    | (($x & 0xC0000000) >> 6) | (($x & 0x3F000000) << 2)
            ) & ParagonIE_Sodium_Core_Util::U32_MAX;
        }
        return $this;
    }

    /**
     * @param int $x
     * @return int
     */
    public static function rotr16($x)
    {
        return (($x << 16) & ParagonIE_Sodium_Core_Util::U32_MAX) | ($x >> 16);
    }

    /**
     * @return self
     */
    public function mixColumns()
    {
        $q0 = $this->values[0];
        $q1 = $this->values[1];
        $q2 = $this->values[2];
        $q3 = $this->values[3];
        $q4 = $this->values[4];
        $q5 = $this->values[5];
        $q6 = $this->values[6];
        $q7 = $this->values[7];
        $r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;

        $this->values[0] = $q7 ^ $r7 ^ $r0 ^ self::rotr16($q0 ^ $r0);
        $this->values[1] = $q0 ^ $r0 ^ $q7 ^ $r7 ^ $r1 ^ self::rotr16($q1 ^ $r1);
        $this->values[2] = $q1 ^ $r1 ^ $r2 ^ self::rotr16($q2 ^ $r2);
        $this->values[3] = $q2 ^ $r2 ^ $q7 ^ $r7 ^ $r3 ^ self::rotr16($q3 ^ $r3);
        $this->values[4] = $q3 ^ $r3 ^ $q7 ^ $r7 ^ $r4 ^ self::rotr16($q4 ^ $r4);
        $this->values[5] = $q4 ^ $r4 ^ $r5 ^ self::rotr16($q5 ^ $r5);
        $this->values[6] = $q5 ^ $r5 ^ $r6 ^ self::rotr16($q6 ^ $r6);
        $this->values[7] = $q6 ^ $r6 ^ $r7 ^ self::rotr16($q7 ^ $r7);
        return $this;
    }

    /**
     * @return self
     */
    public function inverseMixColumns()
    {
        $q0 = $this->values[0];
        $q1 = $this->values[1];
        $q2 = $this->values[2];
        $q3 = $this->values[3];
        $q4 = $this->values[4];
        $q5 = $this->values[5];
        $q6 = $this->values[6];
        $q7 = $this->values[7];
        $r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
        $r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;

        $this->values[0] = $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r5 ^ $r7 ^ self::rotr16($q0 ^ $q5 ^ $q6 ^ $r0 ^ $r5);
        $this->values[1] = $q0 ^ $q5 ^ $r0 ^ $r1 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q5 ^ $q7 ^ $r1 ^ $r5 ^ $r6);
        $this->values[2] = $q0 ^ $q1 ^ $q6 ^ $r1 ^ $r2 ^ $r6 ^ $r7 ^ self::rotr16($q0 ^ $q2 ^ $q6 ^ $r2 ^ $r6 ^ $r7);
        $this->values[3] = $q0 ^ $q1 ^ $q2 ^ $q5 ^ $q6 ^ $r0 ^ $r2 ^ $r3 ^ $r5 ^ self::rotr16($q0 ^ $q1 ^ $q3 ^ $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r3 ^ $r5 ^ $r7);
        $this->values[4] = $q1 ^ $q2 ^ $q3 ^ $q5 ^ $r1 ^ $r3 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q2 ^ $q4 ^ $q5 ^ $q7 ^ $r1 ^ $r4 ^ $r5 ^ $r6);
        $this->values[5] = $q2 ^ $q3 ^ $q4 ^ $q6 ^ $r2 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q2 ^ $q3 ^ $q5 ^ $q6 ^ $r2 ^ $r5 ^ $r6 ^ $r7);
        $this->values[6] = $q3 ^ $q4 ^ $q5 ^ $q7 ^ $r3 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q3 ^ $q4 ^ $q6 ^ $q7 ^ $r3 ^ $r6 ^ $r7);
        $this->values[7] = $q4 ^ $q5 ^ $q6 ^ $r4 ^ $r6 ^ $r7 ^ self::rotr16($q4 ^ $q5 ^ $q7 ^ $r4 ^ $r7);
        return $this;
    }

    /**
     * @return self
     */
    public function inverseShiftRows()
    {
        for ($i = 0; $i < 8; ++$i) {
            $x = $this->values[$i];
            $this->values[$i] = ParagonIE_Sodium_Core_Util::U32_MAX & (
                ($x & 0x000000FF)
                    | (($x & 0x00003F00) << 2) | (($x & 0x0000C000) >> 6)
                    | (($x & 0x000F0000) << 4) | (($x & 0x00F00000) >> 4)
                    | (($x & 0x03000000) << 6) | (($x & 0xFC000000) >> 2)
            );
        }
        return $this;
    }
}
                                                                                                                                                                                                                                                                                              XChaCha20.php                                                                                       0000644                 00000000146 15172703540 0006663 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class XChaCha20 extends \ParagonIE_Sodium_Core_XChaCha20
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                          AEGIS256.php                                                                                        0000644                 00000007016 15172703540 0006352 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
    define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
}
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
    define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
}

class ParagonIE_Sodium_Core_AEGIS256 extends ParagonIE_Sodium_Core_AES
{
    /**
     * @param string $ct
     * @param string $tag
     * @param string $ad
     * @param string $key
     * @param string $nonce
     * @return string
     * @throws SodiumException
     */
    public static function decrypt($ct, $tag, $ad, $key, $nonce)
    {
        $state = self::init($key, $nonce);

        // ad_blocks = Split(ZeroPad(ad, 128), 128)
        $ad_blocks = (self::strlen($ad) + 15) >> 4;
        // for ai in ad_blocks:
        //     Absorb(ai)
        for ($i = 0; $i < $ad_blocks; ++$i) {
            $ai = self::substr($ad, $i << 4, 16);
            if (self::strlen($ai) < 16) {
                $ai = str_pad($ai, 16, "\0", STR_PAD_RIGHT);
            }
            $state->absorb($ai);
        }

        $msg = '';
        $cn = self::strlen($ct) & 15;
        $ct_blocks = self::strlen($ct) >> 4;
        // ct_blocks = Split(ZeroPad(ct, 128), 128)
        // cn = Tail(ct, |ct| mod 128)
        for ($i = 0; $i < $ct_blocks; ++$i) {
            $msg .= $state->dec(self::substr($ct, $i << 4, 16));
        }
        // if cn is not empty:
        //   msg = msg || DecPartial(cn)
        if ($cn) {
            $start = $ct_blocks << 4;
            $msg .= $state->decPartial(self::substr($ct, $start, $cn));
        }
        $expected_tag = $state->finalize(
            self::strlen($ad) << 3,
            self::strlen($msg) << 3
        );
        if (!self::hashEquals($expected_tag, $tag)) {
            try {
                // The RFC says to erase msg, so we shall try:
                ParagonIE_Sodium_Compat::memzero($msg);
            } catch (SodiumException $ex) {
                // Do nothing if we cannot memzero
            }
            throw new SodiumException('verification failed');
        }
        return $msg;
    }

    /**
     * @param string $msg
     * @param string $ad
     * @param string $key
     * @param string $nonce
     * @return array
     * @throws SodiumException
     */
    public static function encrypt($msg, $ad, $key, $nonce)
    {
        $state = self::init($key, $nonce);
        $ad_len = self::strlen($ad);
        $msg_len = self::strlen($msg);
        $ad_blocks = ($ad_len + 15) >> 4;
        for ($i = 0; $i < $ad_blocks; ++$i) {
            $ai = self::substr($ad, $i << 4, 16);
            if (self::strlen($ai) < 16) {
                $ai = str_pad($ai, 16, "\0", STR_PAD_RIGHT);
            }
            $state->absorb($ai);
        }

        $ct = '';
        $msg_blocks = ($msg_len + 15) >> 4;
        for ($i = 0; $i < $msg_blocks; ++$i) {
            $xi = self::substr($msg, $i << 4, 16);
            if (self::strlen($xi) < 16) {
                $xi = str_pad($xi, 16, "\0", STR_PAD_RIGHT);
            }
            $ct .= $state->enc($xi);
        }
        $tag = $state->finalize(
            $ad_len << 3,
            $msg_len << 3
        );
        return array(
            self::substr($ct, 0, $msg_len),
            $tag
        );

    }

    /**
     * @param string $key
     * @param string $nonce
     * @return ParagonIE_Sodium_Core_AEGIS_State256
     */
    public static function init($key, $nonce)
    {
        return ParagonIE_Sodium_Core_AEGIS_State256::init($key, $nonce);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  Base64/UrlSafe.php                                                                                  0000644                 00000020443 15172703540 0007651 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/**
 * Class ParagonIE_Sodium_Core_Base64UrlSafe
 *
 *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 */
class ParagonIE_Sodium_Core_Base64_UrlSafe
{
    // COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE
    /**
     * Encode into Base64
     *
     * Base64 character set "[A-Z][a-z][0-9]+/"
     *
     * @param string $src
     * @return string
     * @throws TypeError
     */
    public static function encode($src)
    {
        return self::doEncode($src, true);
    }

    /**
     * Encode into Base64, no = padding
     *
     * Base64 character set "[A-Z][a-z][0-9]+/"
     *
     * @param string $src
     * @return string
     * @throws TypeError
     */
    public static function encodeUnpadded($src)
    {
        return self::doEncode($src, false);
    }

    /**
     * @param string $src
     * @param bool $pad   Include = padding?
     * @return string
     * @throws TypeError
     */
    protected static function doEncode($src, $pad = true)
    {
        $dest = '';
        $srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
        // Main loop (no padding):
        for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
            $b0 = $chunk[1];
            $b1 = $chunk[2];
            $b2 = $chunk[3];

            $dest .=
                self::encode6Bits(               $b0 >> 2       ) .
                self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
                self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
                self::encode6Bits(  $b2                     & 63);
        }
        // The last chunk, which may have padding:
        if ($i < $srcLen) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
            $b0 = $chunk[1];
            if ($i + 1 < $srcLen) {
                $b1 = $chunk[2];
                $dest .=
                    self::encode6Bits($b0 >> 2) .
                    self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
                    self::encode6Bits(($b1 << 2) & 63);
                if ($pad) {
                    $dest .= '=';
                }
            } else {
                $dest .=
                    self::encode6Bits( $b0 >> 2) .
                    self::encode6Bits(($b0 << 4) & 63);
                if ($pad) {
                    $dest .= '==';
                }
            }
        }
        return $dest;
    }

    /**
     * decode from base64 into binary
     *
     * Base64 character set "./[A-Z][a-z][0-9]"
     *
     * @param string $src
     * @param bool $strictPadding
     * @return string
     * @throws RangeException
     * @throws TypeError
     * @psalm-suppress RedundantCondition
     */
    public static function decode($src, $strictPadding = false)
    {
        // Remove padding
        $srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
        if ($srcLen === 0) {
            return '';
        }

        if ($strictPadding) {
            if (($srcLen & 3) === 0) {
                if ($src[$srcLen - 1] === '=') {
                    $srcLen--;
                    if ($src[$srcLen - 1] === '=') {
                        $srcLen--;
                    }
                }
            }
            if (($srcLen & 3) === 1) {
                throw new RangeException(
                    'Incorrect padding'
                );
            }
            if ($src[$srcLen - 1] === '=') {
                throw new RangeException(
                    'Incorrect padding'
                );
            }
        } else {
            $src = rtrim($src, '=');
            $srcLen =  ParagonIE_Sodium_Core_Util::strlen($src);
        }

        $err = 0;
        $dest = '';
        // Main loop (no padding):
        for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
            $c0 = self::decode6Bits($chunk[1]);
            $c1 = self::decode6Bits($chunk[2]);
            $c2 = self::decode6Bits($chunk[3]);
            $c3 = self::decode6Bits($chunk[4]);

            $dest .= pack(
                'CCC',
                ((($c0 << 2) | ($c1 >> 4)) & 0xff),
                ((($c1 << 4) | ($c2 >> 2)) & 0xff),
                ((($c2 << 6) | $c3) & 0xff)
            );
            $err |= ($c0 | $c1 | $c2 | $c3) >> 8;
        }
        // The last chunk, which may have padding:
        if ($i < $srcLen) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
            $c0 = self::decode6Bits($chunk[1]);

            if ($i + 2 < $srcLen) {
                $c1 = self::decode6Bits($chunk[2]);
                $c2 = self::decode6Bits($chunk[3]);
                $dest .= pack(
                    'CC',
                    ((($c0 << 2) | ($c1 >> 4)) & 0xff),
                    ((($c1 << 4) | ($c2 >> 2)) & 0xff)
                );
                $err |= ($c0 | $c1 | $c2) >> 8;
            } elseif ($i + 1 < $srcLen) {
                $c1 = self::decode6Bits($chunk[2]);
                $dest .= pack(
                    'C',
                    ((($c0 << 2) | ($c1 >> 4)) & 0xff)
                );
                $err |= ($c0 | $c1) >> 8;
            } elseif ($i < $srcLen && $strictPadding) {
                $err |= 1;
            }
        }
        /** @var bool $check */
        $check = ($err === 0);
        if (!$check) {
            throw new RangeException(
                'Base64::decode() only expects characters in the correct base64 alphabet'
            );
        }
        return $dest;
    }

    /**
     * @param string $encodedString
     * @return string
     */
    public static function decodeNoPadding(
        #[SensitiveParameter]
        $encodedString
    ) {
        $srcLen = strlen($encodedString);
        if ($srcLen === 0) {
            return '';
        }
        if (($srcLen & 3) === 0) {
            // If $strLen is not zero, and it is divisible by 4, then it's at least 4.
            if ($encodedString[$srcLen - 1] === '=' || $encodedString[$srcLen - 2] === '=') {
                throw new InvalidArgumentException(
                    "decodeNoPadding() doesn't tolerate padding"
                );
            }
        }
        return self::decode(
            $encodedString,
            true
        );
    }

    // COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE
    /**
     * Uses bitwise operators instead of table-lookups to turn 6-bit integers
     * into 8-bit integers.
     *
     * Base64 character set:
     * [A-Z]      [a-z]      [0-9]      +     /
     * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
     *
     * @param int $src
     * @return int
     */
    protected static function decode6Bits($src)
    {
        $ret = -1;

        // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);

        // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70);

        // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
        $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5);

        // if ($src == 0x2c) $ret += 62 + 1;
        $ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63;

        // if ($src == 0x5f) ret += 63 + 1;
        $ret += (((0x5e - $src) & ($src - 0x60)) >> 8) & 64;

        return $ret;
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
     * into 6-bit integers.
     *
     * @param int $src
     * @return string
     */
    protected static function encode6Bits($src)
    {
        $diff = 0x41;

        // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
        $diff += ((25 - $src) >> 8) & 6;

        // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
        $diff -= ((51 - $src) >> 8) & 75;

        // if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13
        $diff -= ((61 - $src) >> 8) & 13;

        // if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3
        $diff += ((62 - $src) >> 8) & 49;

        return pack('C', $src + $diff);
    }
}
                                                                                                                                                                                                                             Base64/Original.php                                                                                 0000644                 00000020434 15172703540 0010054 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/**
 * Class ParagonIE_Sodium_Core_Base64
 *
 *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 */
class ParagonIE_Sodium_Core_Base64_Original
{
    // COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE
    /**
     * Encode into Base64
     *
     * Base64 character set "[A-Z][a-z][0-9]+/"
     *
     * @param string $src
     * @return string
     * @throws TypeError
     */
    public static function encode($src)
    {
        return self::doEncode($src, true);
    }

    /**
     * Encode into Base64, no = padding
     *
     * Base64 character set "[A-Z][a-z][0-9]+/"
     *
     * @param string $src
     * @return string
     * @throws TypeError
     */
    public static function encodeUnpadded($src)
    {
        return self::doEncode($src, false);
    }

    /**
     * @param string $src
     * @param bool $pad   Include = padding?
     * @return string
     * @throws TypeError
     */
    protected static function doEncode($src, $pad = true)
    {
        $dest = '';
        $srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
        // Main loop (no padding):
        for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
            $b0 = $chunk[1];
            $b1 = $chunk[2];
            $b2 = $chunk[3];

            $dest .=
                self::encode6Bits(               $b0 >> 2       ) .
                self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
                self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
                self::encode6Bits(  $b2                     & 63);
        }
        // The last chunk, which may have padding:
        if ($i < $srcLen) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
            $b0 = $chunk[1];
            if ($i + 1 < $srcLen) {
                $b1 = $chunk[2];
                $dest .=
                    self::encode6Bits($b0 >> 2) .
                    self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
                    self::encode6Bits(($b1 << 2) & 63);
                if ($pad) {
                    $dest .= '=';
                }
            } else {
                $dest .=
                    self::encode6Bits( $b0 >> 2) .
                    self::encode6Bits(($b0 << 4) & 63);
                if ($pad) {
                    $dest .= '==';
                }
            }
        }
        return $dest;
    }

    /**
     * decode from base64 into binary
     *
     * Base64 character set "./[A-Z][a-z][0-9]"
     *
     * @param string $src
     * @param bool $strictPadding
     * @return string
     * @throws RangeException
     * @throws TypeError
     * @psalm-suppress RedundantCondition
     */
    public static function decode($src, $strictPadding = false)
    {
        // Remove padding
        $srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
        if ($srcLen === 0) {
            return '';
        }

        if ($strictPadding) {
            if (($srcLen & 3) === 0) {
                if ($src[$srcLen - 1] === '=') {
                    $srcLen--;
                    if ($src[$srcLen - 1] === '=') {
                        $srcLen--;
                    }
                }
            }
            if (($srcLen & 3) === 1) {
                throw new RangeException(
                    'Incorrect padding'
                );
            }
            if ($src[$srcLen - 1] === '=') {
                throw new RangeException(
                    'Incorrect padding'
                );
            }
        } else {
            $src = rtrim($src, '=');
            $srcLen =  ParagonIE_Sodium_Core_Util::strlen($src);
        }

        $err = 0;
        $dest = '';
        // Main loop (no padding):
        for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
            $c0 = self::decode6Bits($chunk[1]);
            $c1 = self::decode6Bits($chunk[2]);
            $c2 = self::decode6Bits($chunk[3]);
            $c3 = self::decode6Bits($chunk[4]);

            $dest .= pack(
                'CCC',
                ((($c0 << 2) | ($c1 >> 4)) & 0xff),
                ((($c1 << 4) | ($c2 >> 2)) & 0xff),
                ((($c2 << 6) | $c3) & 0xff)
            );
            $err |= ($c0 | $c1 | $c2 | $c3) >> 8;
        }
        // The last chunk, which may have padding:
        if ($i < $srcLen) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
            $c0 = self::decode6Bits($chunk[1]);

            if ($i + 2 < $srcLen) {
                $c1 = self::decode6Bits($chunk[2]);
                $c2 = self::decode6Bits($chunk[3]);
                $dest .= pack(
                    'CC',
                    ((($c0 << 2) | ($c1 >> 4)) & 0xff),
                    ((($c1 << 4) | ($c2 >> 2)) & 0xff)
                );
                $err |= ($c0 | $c1 | $c2) >> 8;
            } elseif ($i + 1 < $srcLen) {
                $c1 = self::decode6Bits($chunk[2]);
                $dest .= pack(
                    'C',
                    ((($c0 << 2) | ($c1 >> 4)) & 0xff)
                );
                $err |= ($c0 | $c1) >> 8;
            } elseif ($i < $srcLen && $strictPadding) {
                $err |= 1;
            }
        }
        /** @var bool $check */
        $check = ($err === 0);
        if (!$check) {
            throw new RangeException(
                'Base64::decode() only expects characters in the correct base64 alphabet'
            );
        }
        return $dest;
    }

    /**
     * @param string $encodedString
     * @return string
     */
    public static function decodeNoPadding(
        #[SensitiveParameter]
        $encodedString
    ) {
        $srcLen = strlen($encodedString);
        if ($srcLen === 0) {
            return '';
        }
        if (($srcLen & 3) === 0) {
            // If $strLen is not zero, and it is divisible by 4, then it's at least 4.
            if ($encodedString[$srcLen - 1] === '=' || $encodedString[$srcLen - 2] === '=') {
                throw new InvalidArgumentException(
                    "decodeNoPadding() doesn't tolerate padding"
                );
            }
        }
        return self::decode(
            $encodedString,
            true
        );
    }
    // COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE

    /**
     * Uses bitwise operators instead of table-lookups to turn 6-bit integers
     * into 8-bit integers.
     *
     * Base64 character set:
     * [A-Z]      [a-z]      [0-9]      +     /
     * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
     *
     * @param int $src
     * @return int
     */
    protected static function decode6Bits($src)
    {
        $ret = -1;

        // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);

        // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70);

        // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
        $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5);

        // if ($src == 0x2b) $ret += 62 + 1;
        $ret += (((0x2a - $src) & ($src - 0x2c)) >> 8) & 63;

        // if ($src == 0x2f) ret += 63 + 1;
        $ret += (((0x2e - $src) & ($src - 0x30)) >> 8) & 64;

        return $ret;
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
     * into 6-bit integers.
     *
     * @param int $src
     * @return string
     */
    protected static function encode6Bits($src)
    {
        $diff = 0x41;

        // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
        $diff += ((25 - $src) >> 8) & 6;

        // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
        $diff -= ((51 - $src) >> 8) & 75;

        // if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15
        $diff -= ((61 - $src) >> 8) & 15;

        // if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3
        $diff += ((62 - $src) >> 8) & 3;

        return pack('C', $src + $diff);
    }
}
                                                                                                                                                                                                                                    Util.php                                                                                            0000644                 00000000134 15172703540 0006174 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class Util extends \ParagonIE_Sodium_Core_Util
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                                    SecretStream/State.php                                                                              0000644                 00000007050 15172703540 0010744 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/**
 * Class ParagonIE_Sodium_Core_SecretStream_State
 */
class ParagonIE_Sodium_Core_SecretStream_State
{
    /** @var string $key */
    protected $key;

    /** @var int $counter */
    protected $counter;

    /** @var string $nonce */
    protected $nonce;

    /** @var string $_pad */
    protected $_pad;

    /**
     * ParagonIE_Sodium_Core_SecretStream_State constructor.
     * @param string $key
     * @param string|null $nonce
     */
    public function __construct($key, $nonce = null)
    {
        $this->key = $key;
        $this->counter = 1;
        if (is_null($nonce)) {
            $nonce = str_repeat("\0", 12);
        }
        $this->nonce = str_pad($nonce, 12, "\0", STR_PAD_RIGHT);;
        $this->_pad = str_repeat("\0", 4);
    }

    /**
     * @return self
     */
    public function counterReset()
    {
        $this->counter = 1;
        $this->_pad = str_repeat("\0", 4);
        return $this;
    }

    /**
     * @return string
     */
    public function getKey()
    {
        return $this->key;
    }

    /**
     * @return string
     */
    public function getCounter()
    {
        return ParagonIE_Sodium_Core_Util::store32_le($this->counter);
    }

    /**
     * @return string
     */
    public function getNonce()
    {
        if (!is_string($this->nonce)) {
            $this->nonce = str_repeat("\0", 12);
        }
        if (ParagonIE_Sodium_Core_Util::strlen($this->nonce) !== 12) {
            $this->nonce = str_pad($this->nonce, 12, "\0", STR_PAD_RIGHT);
        }
        return $this->nonce;
    }

    /**
     * @return string
     */
    public function getCombinedNonce()
    {
        return $this->getCounter() .
            ParagonIE_Sodium_Core_Util::substr($this->getNonce(), 0, 8);
    }

    /**
     * @return self
     */
    public function incrementCounter()
    {
        ++$this->counter;
        return $this;
    }

    /**
     * @return bool
     */
    public function needsRekey()
    {
        return ($this->counter & 0xffff) === 0;
    }

    /**
     * @param string $newKeyAndNonce
     * @return self
     */
    public function rekey($newKeyAndNonce)
    {
        $this->key = ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 0, 32);
        $this->nonce = str_pad(
            ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 32),
            12,
            "\0",
            STR_PAD_RIGHT
        );
        return $this;
    }

    /**
     * @param string $str
     * @return self
     */
    public function xorNonce($str)
    {
        $this->nonce = ParagonIE_Sodium_Core_Util::xorStrings(
            $this->getNonce(),
            str_pad(
                ParagonIE_Sodium_Core_Util::substr($str, 0, 8),
                12,
                "\0",
                STR_PAD_RIGHT
            )
        );
        return $this;
    }

    /**
     * @param string $string
     * @return self
     */
    public static function fromString($string)
    {
        $state = new ParagonIE_Sodium_Core_SecretStream_State(
            ParagonIE_Sodium_Core_Util::substr($string, 0, 32)
        );
        $state->counter = ParagonIE_Sodium_Core_Util::load_4(
            ParagonIE_Sodium_Core_Util::substr($string, 32, 4)
        );
        $state->nonce = ParagonIE_Sodium_Core_Util::substr($string, 36, 12);
        $state->_pad = ParagonIE_Sodium_Core_Util::substr($string, 48, 8);
        return $state;
    }

    /**
     * @return string
     */
    public function toString()
    {
        return $this->key .
            $this->getCounter() .
            $this->nonce .
            $this->_pad;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        Xsalsa20.php                                                                                        0000644                 00000000144 15172731233 0006655 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
namespace ParagonIE\Sodium\Core;

class Xsalsa20 extends \ParagonIE_Sodium_Core_XSalsa20
{

}
                                                                                                                                                                                                                                                                                                                                                                                                                            Upgrade/UpgradeFunctions.php                                                                        0000644                 00000012036 15174703154 0012135 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/**
 * @package   Duplicator
 * @copyright (c) 2022, Snap Creek LLC
 */

namespace Duplicator\Core\Upgrade;

use DUP_Settings;
use Duplicator\Utils\Email\EmailSummary;
use Duplicator\Libs\Snap\SnapIO;
use DUP_Log;
use Exception;

/**
 * Utility class managing actions when the plugin is updated
 */
class UpgradeFunctions
{
    const LAST_VERSION_EMAIL_SUMMARY_WRONG_KEY = '1.5.6.1';
    const FIRST_VERSION_NEW_STORAGE_POSITION   = '1.3.35';
    const FIRST_VERSION_FOLDER_MIGRATION       = '1.5.14';
    const FIRST_VERSION_WITH_LOGS_SUBFOLDER    = '1.5.14-beta1';

    /**
    * This function is executed when the plugin is activated and
    * every time the version saved in the wp_options is different from the plugin version both in upgrade and downgrade.
    *
    * @param false|string $currentVersion current Duplicator version, false if is first installation
    * @param string       $newVersion     new Duplicator Version
    *
    * @return void
    */
    public static function performUpgrade($currentVersion, $newVersion): void
    {
        self::updateStoragePostition($currentVersion);
        self::emailSummaryOptKeyUpdate($currentVersion);
        self::migrateStorageFolders($currentVersion, $newVersion);
        self::migrateLogsToSubfolder($currentVersion);
    }

    /**
     * Update email summary option key seperator from '-' to '_'
     *
     * @param false|string $currentVersion current Duplicator version, false if is first installation
     *
     * @return void
     */
    private static function emailSummaryOptKeyUpdate($currentVersion): void
    {
        if ($currentVersion == false || version_compare($currentVersion, self::LAST_VERSION_EMAIL_SUMMARY_WRONG_KEY, '>')) {
            return;
        }

        if (($data = get_option(EmailSummary::INFO_OPT_OLD_KEY)) !== false) {
            update_option(EmailSummary::INFO_OPT_KEY, $data);
            delete_option(EmailSummary::INFO_OPT_OLD_KEY);
        }
    }

    /**
     * Update storage position option
     *
     * @param false|string $currentVersion current Duplicator version, false if is first installation
     *
     * @return void
     */
    private static function updateStoragePostition($currentVersion): void
    {
        //PRE 1.3.35
        //Do not update to new wp-content storage till after
        if ($currentVersion !== false && version_compare($currentVersion, self::FIRST_VERSION_NEW_STORAGE_POSITION, '<')) {
            DUP_Settings::Set('storage_position', DUP_Settings::STORAGE_POSITION_LEGACY);
        }
    }

    /**
     * Migrate storage folders from legacy to new location
     *
     * @param false|string $currentVersion current Duplicator version, false if first install
     *
     * @return void
     */
    private static function migrateStorageFolders($currentVersion): void
    {
        // Skip on fresh installs or if already past migration version
        if ($currentVersion === false || version_compare($currentVersion, self::FIRST_VERSION_FOLDER_MIGRATION, '>=')) {
            return;
        }

        // If storage position is already set to new, do not migrate
        if (DUP_Settings::Get('storage_position') === DUP_Settings::STORAGE_POSITION_WP_CONTENT) {
            return;
        }

        // Force using wp-content storage position
        DUP_Settings::setStoragePosition(DUP_Settings::STORAGE_POSITION_WP_CONTENT);
        DUP_Settings::Save();
    }

    /**
     * Migrate existing log files from root directory to logs subfolder
     *
     * @param false|string $currentVersion current Duplicator version, false if is first installation
     *
     * @return void
     */
    private static function migrateLogsToSubfolder($currentVersion): void
    {
        if ($currentVersion === false || version_compare($currentVersion, self::FIRST_VERSION_WITH_LOGS_SUBFOLDER, '>=')) {
            return;
        }

        try {
            DUP_Log::Trace("MIGRATION: Moving log files to logs subfolder");

            // Ensure logs directory exists
            if (!file_exists(DUP_Settings::getSsdirLogsPath())) {
                SnapIO::dirWriteCheckOrMkdir(DUP_Settings::getSsdirLogsPath(), 'u+rwx');
            }

            // Use SnapIO::regexGlob for more robust file discovery
            $logFiles = SnapIO::regexGlob(DUP_Settings::getSsdirPath(), [
                'regexFile'   => [
                    '/.*\.log$/',
                    '/.*\.log1$/',
                ],
                'regexFolder' => false,
                'recursive'   => false,
            ]);

            $migratedCount = 0;
            foreach ($logFiles as $oldPath) {
                $filename = basename($oldPath);
                $newPath  = DUP_Settings::getSsdirLogsPath() . '/' . $filename;

                if (SnapIO::rename($oldPath, $newPath)) {
                    $migratedCount++;
                }
            }

            DUP_Log::Trace("MIGRATION: Moved {$migratedCount} log files to logs subfolder - old location is now clean");
        } catch (Exception $e) {
            DUP_Log::Trace("MIGRATION: Error moving log files: " . $e->getMessage());
        }
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  Controllers/ControllersManager.php                                                                  0000644                 00000014576 15174703154 0013410 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/**
 * Singlethon class that manages the various controllers of the administration of wordpress
 *
 * @package   Duplicator
 * @copyright (c) 2021, Snapcreek LLC
 */

namespace Duplicator\Core\Controllers;

use Duplicator\Libs\Snap\SnapUtil;

final class ControllersManager
{
    const MAIN_MENU_SLUG         = 'duplicator';
    const PACKAGES_SUBMENU_SLUG  = 'duplicator';
    const IMPORT_SUBMENU_SLUG    = 'duplicator-import';
    const SCHEDULES_SUBMENU_SLUG = 'duplicator-schedules';
    const STAGING_SUBMENU_SLUG   = 'duplicator-staging';
    const STORAGE_SUBMENU_SLUG   = 'duplicator-storage';
    const ABOUT_US_SUBMENU_SLUG  = 'duplicator-about-us';
    const TEMPLATES_SUBMENU_SLUG = 'duplicator-templates';
    const TOOLS_SUBMENU_SLUG     = 'duplicator-tools';
    const SETTINGS_SUBMENU_SLUG  = 'duplicator-settings';
    const DEBUG_SUBMENU_SLUG     = 'duplicator-debug';
    const UPSELL_SUBMENU_SLUG    = 'duplicator-pro';

    const QUERY_STRING_MENU_KEY_L1     = 'page';
    const QUERY_STRING_MENU_KEY_L2     = 'tab';
    const QUERY_STRING_MENU_KEY_L3     = 'subtab';
    const QUERY_STRING_MENU_KEY_ACTION = 'action';

    /**
     * Return current menu levels
     *
     * @return string[]
     */
    public static function getMenuLevels()
    {
        $result  = array();
        $exChars = '-_';
        $result[self::QUERY_STRING_MENU_KEY_L1] = SnapUtil::sanitizeStrictInput(
            SnapUtil::INPUT_REQUEST,
            self::QUERY_STRING_MENU_KEY_L1,
            null,
            $exChars
        );
        $result[self::QUERY_STRING_MENU_KEY_L2] = SnapUtil::sanitizeStrictInput(
            SnapUtil::INPUT_REQUEST,
            self::QUERY_STRING_MENU_KEY_L2,
            null,
            $exChars
        );
        $result[self::QUERY_STRING_MENU_KEY_L3] = SnapUtil::sanitizeStrictInput(
            SnapUtil::INPUT_REQUEST,
            self::QUERY_STRING_MENU_KEY_L3,
            null,
            $exChars
        );
        return $result;
    }

    /**
     * Return true if current page is a duplicator page
     *
     * @return boolean
     */
    public static function isDuplicatorPage()
    {
        if (!is_admin()) {
            return false;
        }

        switch (SnapUtil::sanitizeStrictInput(SnapUtil::INPUT_REQUEST, 'page', '', '-_ ')) {
            case self::MAIN_MENU_SLUG:
            case self::PACKAGES_SUBMENU_SLUG:
            case self::IMPORT_SUBMENU_SLUG:
            case self::SCHEDULES_SUBMENU_SLUG:
            case self::STAGING_SUBMENU_SLUG:
            case self::STORAGE_SUBMENU_SLUG:
            case self::ABOUT_US_SUBMENU_SLUG:
            case self::TEMPLATES_SUBMENU_SLUG:
            case self::TOOLS_SUBMENU_SLUG:
            case self::SETTINGS_SUBMENU_SLUG:
            case self::DEBUG_SUBMENU_SLUG:
            case self::UPSELL_SUBMENU_SLUG:
                return true;
            default:
                return false;
        }
    }

    /**
     * Return current action key or false if not exists
     *
     * @return string|bool
     */
    public static function getAction()
    {
        return SnapUtil::sanitizeStrictInput(
            SnapUtil::INPUT_REQUEST,
            self::QUERY_STRING_MENU_KEY_ACTION,
            false,
            '-_'
        );
    }

    /**
     * Check current page
     *
     * @param string      $page  page key
     * @param null|string $tabL1 tab level 1 key, null not check
     * @param null|string $tabL2 tab level 12key, null not check
     *
     * @return boolean
     */
    public static function isCurrentPage($page, $tabL1 = null, $tabL2 = null)
    {
        $levels = self::getMenuLevels();

        if ($page !== $levels[self::QUERY_STRING_MENU_KEY_L1]) {
            return false;
        }

        if (!is_null($tabL1) && $tabL1 !== $levels[self::QUERY_STRING_MENU_KEY_L2]) {
            return false;
        }

        if (!is_null($tabL1) && !is_null($tabL2) && $tabL2 !== $levels[self::QUERY_STRING_MENU_KEY_L3]) {
            return false;
        }

        return true;
    }

    /**
     * Return current menu page URL
     *
     * @param array $extraData extra value in query string key=val
     *
     * @return string
     */
    public static function getCurrentLink($extraData = array())
    {
        $levels = self::getMenuLevels();
        return self::getMenuLink(
            $levels[self::QUERY_STRING_MENU_KEY_L1],
            $levels[self::QUERY_STRING_MENU_KEY_L2],
            $levels[self::QUERY_STRING_MENU_KEY_L3],
            $extraData
        );
    }

    /**
     * Return menu page URL
     *
     * @param string $page      page slug
     * @param string $subL2     tab level 1 slug, null not set
     * @param string $subL3     tab level 2 slug, null not set
     * @param array  $extraData extra value in query string key=val
     * @param bool   $relative  if true return relative path or absolute
     *
     * @return string
     */
    public static function getMenuLink($page, $subL2 = null, $subL3 = null, $extraData = array(), $relative = true)
    {
        $data = $extraData;

        $data[self::QUERY_STRING_MENU_KEY_L1] = $page;

        if (!empty($subL2)) {
            $data[self::QUERY_STRING_MENU_KEY_L2] = $subL2;
        }

        if (!empty($subL3)) {
            $data[self::QUERY_STRING_MENU_KEY_L3] = $subL3;
        }

        if ($relative) {
            $url = self_admin_url('admin.php', 'relative');
        } else {
            if (is_multisite()) {
                $url = network_admin_url('admin.php');
            } else {
                $url = admin_url('admin.php');
            }
        }
        return $url . '?' . http_build_query($data);
    }

    /**
     * Return create package link
     *
     * @return string
     */
    public static function getPackageBuildUrl()
    {
        return self::getMenuLink(
            self::PACKAGES_SUBMENU_SLUG,
            'new1',
            null,
            array(
                'inner_page' => 'new1',
                '_wpnonce' => wp_create_nonce('new1-package')
            )
        );
    }

    /**
     * Return package detail link
     *
     * @param int $packageId package id
     *
     * @return string
     */
    public static function getPackageDetailUrl($packageId)
    {
        return self::getMenuLink(
            self::PACKAGES_SUBMENU_SLUG,
            'detail',
            null,
            array(
                'action' => 'detail',
                'id'     => $packageId
            )
        );
    }
}
                                                                                                                                  MigrationMng.php                                                                                    0000644                 00000042324 15174703155 0007665 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/**
 * Utility class managing th emigration data
 */

namespace Duplicator\Core;

use DUP_Archive;
use DUP_CTRL_Tools;
use DUP_Settings;
use DUP_Util;
use Duplicator\Libs\Snap\SnapWP;
use Duplicator\Libs\Snap\SnapIO;
use Duplicator\Utils\CachesPurge\CachesPurge;
use Duplicator\Utils\UsageStatistics\CommStats;
use Duplicator\Utils\UsageStatistics\PluginData;
use Duplicator\Views\AdminNotices;
use Error;
use Exception;

class MigrationMng
{
    const HOOK_FIRST_LOGIN_AFTER_INSTALL = 'duplicator_first_login_after_install';
    const HOOK_BOTTOM_MIGRATION_MESSAGE  = 'duplicator_bottom_migration_message';
    const FIRST_LOGIN_OPTION             = 'duplicator_first_login_after_install';
    const MIGRATION_DATA_OPTION          = 'duplicator_migration_data';
    const CLEAN_INSTALL_REPORT_OPTION    = 'duplicator_clean_install_report';

    /**
     * messages to be displayed in the successful migration box
     *
     * @var array
     */
    protected static $migrationCleanupReport = array(
        'removed' => array(),
        'stored'  => array(),
        'instFile' => array()
    );

    /**
     * Init
     *
     * @return void
     */
    public static function init()
    {
        add_action('admin_init', array(__CLASS__, 'adminInit'));
        add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, function ($migrationData) {
            DUP_Util::initSnapshotDirectory();
        });
        add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'removeFirstLoginOption'));
        add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'renameInstallersPhpFiles'));
        add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'storeMigrationFiles'));
        add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'setDupSettingsAfterInstall'));
        add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'usageStatistics'));
        // save cleanup report after actions
        add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'saveCleanupReport'), 100);

        // LAST BEACAUSE MAKE A WP_REDIRECT
        add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'autoCleanFileAfterInstall'), 99999);
    }

    /**
     * Admin Init function
     *
     * @return void
     */
    public static function adminInit()
    {
        if (self::isFirstLoginAfterInstall()) {
            add_action('current_screen', array(__CLASS__, 'wpAdminHook'), 99999);
            update_option(AdminNotices::OPTION_KEY_MIGRATION_SUCCESS_NOTICE, true);
            do_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, self::getMigrationData());
        }
    }

    /**
     * Admin Hook function
     *
     * @return void
     */
    public static function wpAdminHook()
    {
        if (!DUP_CTRL_Tools::isToolPage()) {
            wp_redirect(DUP_CTRL_Tools::getDiagnosticURL(false));
            exit;
        }
    }

    /**
     *
     * @return boolean
     */
    public static function isFirstLoginAfterInstall()
    {
        if (is_user_logged_in() && get_option(self::FIRST_LOGIN_OPTION, false)) {
            if (is_multisite()) {
                if (is_super_admin()) {
                    return true;
                }
            } else {
                if (current_user_can('manage_options')) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Purge all caches
     *
     * @return string[] // messages
     */
    public static function purgeCaches()
    {
        if (
            self::getMigrationData('restoreBackupMode') ||
            in_array(self::getMigrationData('installType'), array(4,5,6,7)) //update with define when installerstat will be in namespace
        ) {
            return array();
        }

        return CachesPurge::purgeAll();
    }

    /**
     * Clean after install
     *
     * @param array $migrationData migration data
     *
     * @return void
     */
    public static function usageStatistics($migrationData)
    {
        $migrationData = (object) $migrationData;
        PluginData::getInstance()->updateFromMigrateData($migrationData);
        CommStats::installerSend();
    }

    /**
     *
     * @param array $migrationData Migration data
     *
     * @return void
     */
    public static function autoCleanFileAfterInstall($migrationData)
    {
        if ($migrationData == false || $migrationData['cleanInstallerFiles'] == false) {
            return;
        }

        wp_redirect(DUP_CTRL_Tools::getCleanFilesAcrtionUrl(false));
        exit;
    }

    /**
     *
     * @param array $migrationData Migration data
     *
     * @return void
     */
    public static function setDupSettingsAfterInstall($migrationData)
    {
        flush_rewrite_rules(true);
    }

    /**
     * return cleanup report
     *
     * @return array
     */
    public static function getCleanupReport()
    {
        $option = get_option(self::CLEAN_INSTALL_REPORT_OPTION);
        if (is_array($option)) {
            self::$migrationCleanupReport = array_merge(self::$migrationCleanupReport, $option);
        }

        return self::$migrationCleanupReport;
    }

    /**
     * save clean up report in wordpress options
     *
     * @return boolean
     */
    public static function saveCleanupReport()
    {
        return add_option(self::CLEAN_INSTALL_REPORT_OPTION, self::$migrationCleanupReport, '', 'no');
    }

    /**
     *
     * @param array $migrationData Migration data
     *
     * @return void
     */
    public static function removeFirstLoginOption($migrationData)
    {
        delete_option(self::FIRST_LOGIN_OPTION);
    }

    /**
     *
     * @staticvar array $migrationData
     *
     * @param string|null $key Key to get from migration data
     *
     * @return mixed
     */
    public static function getMigrationData($key = null)
    {
        static $migrationData = null;
        if (is_null($migrationData)) {
            $migrationData = get_option(self::MIGRATION_DATA_OPTION, false);
            if (is_string($migrationData)) {
                $migrationData = json_decode($migrationData, true);
            }
        }

        if (is_null($key)) {
            return $migrationData;
        } elseif (isset($migrationData[$key])) {
            return $migrationData[$key];
        } else {
            return false;
        }
    }

    /**
     *
     * @return string
     */
    public static function getSaveModeWarning()
    {
        switch (self::getMigrationData('safeMode')) {
            case 1:
                //safe_mode basic
                return __('NOTICE: Safe mode (Basic) was enabled during install, be sure to re-enable all your plugins.', 'duplicator');
            case 2:
                //safe_mode advance
                return __('NOTICE: Safe mode (Advanced) was enabled during install, be sure to re-enable all your plugins.', 'duplicator');
            case 0:
            default:
                return '';
        }
    }

    /**
     * Check the root path and in case there are installer files without hashes rename them.
     *
     * @param integer $fileTimeDelay If the file is younger than $fileTimeDelay seconds then it is not renamed.
     *
     * @return void
     */
    public static function renameInstallersPhpFiles($fileTimeDelay = 0)
    {
        $fileTimeDelay = is_numeric($fileTimeDelay) ? (int) $fileTimeDelay : 0;

        $pathsTocheck = array(
            SnapIO::safePathTrailingslashit(ABSPATH),
            SnapIO::safePathTrailingslashit(SnapWP::getHomePath()),
            SnapIO::safePathTrailingslashit(WP_CONTENT_DIR)
        );

        $migrationData = self::getMigrationData();
        if (isset($migrationData['installerPath'])) {
            $pathsTocheck[] = SnapIO::safePathTrailingslashit(dirname($migrationData['installerPath']));
        }
        if (isset($migrationData['dupInstallerPath'])) {
            $pathsTocheck[] = SnapIO::safePathTrailingslashit(dirname($migrationData['dupInstallerPath']));
        }
        $pathsTocheck = array_unique($pathsTocheck);

        $filesToCheck = array();
        foreach ($pathsTocheck as $cFolder) {
            if (
                !is_dir($cFolder) ||
                !is_writable($cFolder) // rename permissions
            ) {
                continue;
            }
            $cFile = $cFolder . 'installer.php';
            if (
                !is_file($cFile) ||
                !SnapIO::chmod($cFile, 'u+rw') ||
                !is_readable($cFile)
            ) {
                continue;
            }
            $filesToCheck[] = $cFile;
        }

        $installerTplCheck = '/const\s+ARCHIVE_FILENAME\s*=\s*[\'"](.+?)[\'"]\s*;.*const\s+PACKAGE_HASH\s*=\s*[\'"](.+?)[\'"]\s*;/s';

        foreach ($filesToCheck as $file) {
            $fileName = basename($file);

            if ($fileTimeDelay > 0  && (time() - filemtime($file)) < $fileTimeDelay) {
                continue;
            }

            if (($content = @file_get_contents($file, false, null)) === false) {
                continue;
            }
            $matches = null;
            if (preg_match($installerTplCheck, $content, $matches) !== 1) {
                continue;
            }

            $archiveName = $matches[1];
            $hash        = $matches[2];
            $matches     = null;


            if (preg_match(DUPLICATOR_ARCHIVE_REGEX_PATTERN, $archiveName, $matches) !== 1) {
                if (SnapIO::unlink($file)) {
                    self::$migrationCleanupReport['instFile'][] = "<div class='failure'>"
                        . "<i class='fa fa-check green'></i> "
                        . sprintf(__('Installer file <b>%s</b> removed for security reasons', 'duplicator'), esc_html($fileName))
                        . "</div>";
                } else {
                    self::$migrationCleanupReport['instFile'][] = "<div class='success'>"
                        . '<i class="fa fa-exclamation-triangle red"></i> '
                        . sprintf(__('Can\'t remove installer file <b>%s</b>, please remove it for security reasons', 'duplicator'), esc_html($fileName))
                        . '</div>';
                }
                continue;
            }

            $archiveHash =  $matches[1];
            if (strpos($file, $archiveHash) === false) {
                if (SnapIO::rename($file, dirname($file) . '/' . $archiveHash . '_installer.php', true)) {
                    self::$migrationCleanupReport['instFile'][] = "<div class='failure'>"
                        . "<i class='fa fa-check green'></i> "
                        . sprintf(__('Installer file <b>%s</b> renamed with HASH', 'duplicator'), esc_html($fileName))
                        . "</div>";
                } else {
                    self::$migrationCleanupReport['instFile'][] = "<div class='success'>"
                        . '<i class="fa fa-exclamation-triangle red"></i> '
                        . sprintf(
                            __('Can\'t rename installer file <b>%s</b> with HASH, please remove it for security reasons', 'duplicator'),
                            esc_html($fileName)
                        )
                        . '</div>';
                }
            }
        }
    }

    /**
     *
     * @param array $migrationData Migration data
     *
     * @return void
     */
    public static function storeMigrationFiles($migrationData)
    {
        $ssdInstallerPath = DUP_Settings::getSsdirInstallerPath();
        wp_mkdir_p($ssdInstallerPath);
        SnapIO::emptyDir($ssdInstallerPath);
        SnapIO::createSilenceIndex($ssdInstallerPath);

        $filesToMove = array(
            $migrationData['installerLog'],
            $migrationData['installerBootLog'],
            $migrationData['origFileFolderPath']
        );

        foreach ($filesToMove as $path) {
            if (file_exists($path)) {
                if (SnapIO::rcopy($path, $ssdInstallerPath . '/' . basename($path), true)) {
                    self::$migrationCleanupReport['stored'] = "<div class='success'>"
                        . "<i class='fa fa-check'></i> "
                        . __('Original files folder moved in installer backup directory', 'duplicator') . " - " . esc_html($path) .
                        "</div>";
                } else {
                    self::$migrationCleanupReport['stored'] = "<div class='success'>"
                        . '<i class="fa fa-exclamation-triangle"></i> '
                        . sprintf(__('Can\'t move %s to %s', 'duplicator'), esc_html($path), $ssdInstallerPath)
                        . '</div>';
                }
            }
        }
    }

    /**
     *
     * @return array
     */
    public static function getStoredMigrationLists()
    {
        if (($migrationData = self::getMigrationData()) == false) {
            $filesToCheck = array();
        } else {
            $filesToCheck = array(
                $migrationData['installerLog']       => __('Installer log', 'duplicator'),
                $migrationData['installerBootLog']   => __('Installer boot log', 'duplicator'),
                $migrationData['origFileFolderPath'] => __('Original files folder', 'duplicator')
            );
        }

        $result = array();

        foreach ($filesToCheck as $path => $label) {
            $storedPath = DUP_Settings::getSsdirInstallerPath() . '/' . basename($path);
            if (!file_exists($storedPath)) {
                continue;
            }
            $result[$storedPath] = $label;
        }

        return $result;
    }

    /**
     *
     * @return bool
     */
    public static function haveFileToClean()
    {
        return count(self::checkInstallerFilesList()) > 0;
    }

    /**
     * Gets a list of all the installer files and directory by name and full path
     *
     * @remarks
     *  FILES:      installer.php, installer-backup.php, dup-installer-bootlog__[HASH].txt
     *  DIRS:       dup-installer
     *  Last set is for lazy developer cleanup files that a developer may have
     *  accidentally left around lets be proactive for the user just in case.
     *
     * @return [string] // [file_name]
     */
    public static function getGenericInstallerFiles()
    {
        return array(
            'installer.php',
            '[HASH]installer-backup.php',
            'dup-installer',
            'dup-installer[HASH]',
            'dup-installer-bootlog__[HASH].txt',
            '[HASH]_archive.zip|daf'
        );
    }

    /**
     *
     * @return string[]
     * @throws Exception
     */
    public static function checkInstallerFilesList()
    {
        $migrationData = self::getMigrationData();

        $foldersToChkeck = array(
            SnapIO::safePathTrailingslashit(ABSPATH),
            SnapWP::getHomePath(),
        );

        $result = array();

        if (!empty($migrationData)) {
            if (
                file_exists($migrationData['archivePath']) &&
                !DUP_Archive::isBackupPathChild($migrationData['archivePath'])
            ) {
                $result[] = $migrationData['archivePath'];
            }
            if (
                self::isInstallerFile($migrationData['installerPath']) &&
                !DUP_Archive::isBackupPathChild($migrationData['archivePath'])
            ) {
                $result[] = $migrationData['installerPath'];
            }
            if (file_exists($migrationData['installerBootLog'])) {
                $result[] = $migrationData['installerBootLog'];
            }
            if (file_exists($migrationData['dupInstallerPath'])) {
                $result[] = $migrationData['dupInstallerPath'];
            }
        }

        foreach ($foldersToChkeck as $folder) {
            $result = array_merge($result, SnapIO::regexGlob($folder, array(
                'regexFile'   => array(
                    DUPLICATOR_ARCHIVE_REGEX_PATTERN,
                    DUPLICATOR_INSTALLER_REGEX_PATTERN,
                    DUPLICATOR_DUP_INSTALLER_BOOTLOG_REGEX_PATTERN,
                    DUPLICATOR_DUP_INSTALLER_OWRPARAM_REGEX_PATTERN
                ),
                'regexFolder' => array(
                    DUPLICATOR_DUP_INSTALLER_FOLDER_REGEX_PATTERN
                )
            )));
        }

        $result = array_map(array('Duplicator\\Libs\\Snap\\SnapIO', 'safePathUntrailingslashit'), $result);
        return array_unique($result);
    }

    /**
     * @param $path string Path to check
     *
     * @return bool true if the file at current path is the installer file
     */
    public static function isInstallerFile($path)
    {
        if (!is_file($path) || !is_array($last5Lines = SnapIO::getLastLinesOfFile($path, 5)) || empty($last5Lines)) {
            return false;
        }

        return strpos(implode("", $last5Lines), "DUPLICATOR_INSTALLER_EOF") !== false;
    }

    /**
     * Clear all the installer files and directory
     *
     * @return array
     */
    public static function cleanMigrationFiles()
    {
        $cleanList = self::checkInstallerFilesList();

        $result = array();

        foreach ($cleanList as $path) {
            try {
                $success = (SnapIO::rrmdir($path) !== false);
            } catch (Exception $ex) {
                $success = false;
            } catch (Error $ex) {
                $success = false;
            }

            $result[$path] = $success;
        }

        delete_option(self::CLEAN_INSTALL_REPORT_OPTION);

        return $result;
    }
}
                                                                                                                                                                                                                                                                                                            Unistall.php                                                                                        0000644                 00000001602 15174703155 0007057 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/**
 * Interface that collects the functions of initial duplicator Bootstrap
 *
 * @package   Duplicator
 * @copyright (c) 2022, Snap Creek LLC
 */

namespace Duplicator\Core;

/**
 * Uninstall class
 */
class Unistall
{
    /**
     * Registrer unistall hoosk
     *
     * @return void
     */
    public static function registerHooks()
    {
        if (is_admin()) {
            register_deactivation_hook(DUPLICATOR_LITE_FILE, array(__CLASS__, 'deactivate'));
        }
    }

    /**
     * Deactivation Hook:
     * Hooked into `register_deactivation_hook`.  Routines used to deactivate the plugin
     * For uninstall see uninstall.php  WordPress by default will call the uninstall.php file
     *
     * @return void
     */
    public static function deactivate()
    {
        MigrationMng::renameInstallersPhpFiles();

        do_action('duplicator_after_deactivation');
    }
}
                                                                                                                              Views/TplMng.php                                                                                    0000644                 00000014043 15174703155 0007565 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/**
 * Template view manager
 *
 * @package   Duplicator
 * @copyright (c) 2022, Snap Creek LLC
 */

namespace Duplicator\Core\Views;

use Duplicator\Libs\Snap\SnapJson;

final class TplMng
{
    /** @var ?self */
    private static $instance = null;
    /** @var string */
    private $mainFolder = '';
    /** @var bool */
    private static $stripSpaces = false;
    /** @var mixed[] */
    private $globalData = array();

    /**
     *
     * @return self
     */
    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    /**
     * Class constructor
     */
    private function __construct()
    {
        $this->mainFolder = DUPLICATOR_PLUGIN_PATH . '/template/';
    }

    /**
     * If strip spaces is true in render method spaced between tag are removed
     *
     * @param bool $strip if true strip spaces
     *
     * @return void
     */
    public static function setStripSpaces($strip)
    {
        self::$stripSpaces = (bool) $strip;
    }

    /**
     * Set template global value in template data
     *
     * @param string $key global value key
     * @param mixed  $val value
     *
     * @return void
     */
    public function setGlobalValue($key, $val)
    {
        $this->globalData[$key] = $val;
    }

    /**
     * Remove global value if exist
     *
     * @param string $key gloval value key
     *
     * @return void
     */
    public function unsetGlobalValue($key)
    {
        if (isset($this->globalData[$key])) {
            unset($this->globalData[$key]);
        }
    }

    /**
     * Return true if global values exists
     *
     * @param string $key gloval value key
     *
     * @return bool
     */
    public function hasGlobalValue($key)
    {
        return isset($this->globalData[$key]);
    }

    /**
     * Multiple global data set
     *
     * @param array<string, mixed> $data data tu set in global data
     *
     * @return void
     */
    public function updateGlobalData(array $data = array())
    {
        $this->globalData = array_merge($this->globalData, (array) $data);
    }

    /**
     * Return global data
     *
     * @return array<string, mixed>
     */
    public function getGlobalData()
    {
        return $this->globalData;
    }

    /**
     * Render template
     *
     * @param string               $slugTpl template file is a relative path from root template folder
     * @param array<string, mixed> $args    array key / val where key is the var name in template
     * @param bool                 $echo    if false return template in string
     *
     * @return string
     */
    public function render($slugTpl, $args = array(), $echo = true)
    {
        ob_start();
        if (($renderFile = $this->getFileTemplate($slugTpl)) !== false) {
            $tplData = apply_filters(self::getDataHook($slugTpl), array_merge($this->globalData, $args));
            $tplMng  = $this;
            require($renderFile);
        } else {
            echo '<p>FILE TPL NOT FOUND: ' . $slugTpl . '</p>';
        }
        $renderResult = apply_filters(self::getRenderHook($slugTpl), ob_get_clean());

        if (self::$stripSpaces) {
            $renderResult = preg_replace('~>[\n\s]+<~', '><', $renderResult);
        }
        if ($echo) {
            echo $renderResult;
            return '';
        } else {
            return $renderResult;
        }
    }

    /**
     * Render template in json string
     *
     * @param string               $slugTpl template file is a relative path from root template folder
     * @param array<string, mixed> $args    array key / val where key is the var name in template
     * @param bool                 $echo    if false return template in string
     *
     * @return string
     */
    public function renderJson($slugTpl, $args = array(), $echo = true)
    {
        $renderResult = SnapJson::jsonEncode($this->render($slugTpl, $args, false));
        if ($echo) {
            echo $renderResult;
            return '';
        } else {
            return $renderResult;
        }
    }

    /**
     * Render template apply esc attr
     *
     * @param string               $slugTpl template file is a relative path from root template folder
     * @param array<string, mixed> $args    array key / val where key is the var name in template
     * @param bool                 $echo    if false return template in string
     *
     * @return string
     */
    public function renderEscAttr($slugTpl, $args = array(), $echo = true)
    {
        $renderResult = esc_attr($this->render($slugTpl, $args, false));
        if ($echo) {
            echo $renderResult;
            return '';
        } else {
            return $renderResult;
        }
    }

    /**
     * Get hook unique from template slug
     *
     * @param string $slugTpl template slug
     *
     * @return string
     */
    public static function tplFileToHookSlug($slugTpl)
    {
        return str_replace(array('\\', '/', '.'), '_', $slugTpl);
    }

    /**
     * Return data hook from template slug
     *
     * @param string $slugTpl template slug
     *
     * @return string
     */
    public static function getDataHook($slugTpl)
    {
        return 'duplicator_template_data_' . self::tplFileToHookSlug($slugTpl);
    }

    /**
     * Return render hook from template slug
     *
     * @param string $slugTpl template slug
     *
     * @return string
     */
    public static function getRenderHook($slugTpl)
    {
        return 'duplicator_template_render_' . self::tplFileToHookSlug($slugTpl);
    }

    /**
     * Acctept html of php extensions. if the file have unknown extension automatic add the php extension
     *
     * @param string $slugTpl template slug
     *
     * @return boolean|string return false if don\'t find the template file
     */
    protected function getFileTemplate($slugTpl)
    {
        $fullPath = $this->mainFolder . $slugTpl . '.php';

        if (file_exists($fullPath)) {
            return $fullPath;
        } else {
            return false;
        }
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             Notifications/Notice.php                                                                            0000644                 00000026610 15174703155 0011324 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

namespace Duplicator\Core\Notifications;

class Notice
{
    /**
     * Not dismissible.
     *
     * Constant attended to use as the value of the $args['dismiss'] argument.
     * DISMISS_NONE means that the notice is not dismissible.
     */
    const DISMISS_NONE = 0;

    /**
     * Dismissible global.
     *
     * Constant attended to use as the value of the $args['dismiss'] argument.
     * DISMISS_GLOBAL means that the notice will have the dismiss button, and after clicking this button, the notice will be dismissed for all users.
     */
    const DISMISS_GLOBAL = 1;

    /**
     * Dismissible per user.
     *
     * Constant attended to use as the value of the $args['dismiss'] argument.
     * DISMISS_USER means that the notice will have the dismiss button, and after clicking this button, the notice will be dismissed only for the current user..
     */
    const DISMISS_USER = 2;

    /**
     * Constant for notice type info with gray left border
     */
    const NOTICE_TYPE_INFO = 'info';

    /**
     * Constant for notice type warning with yellow left border
     */
    const NOTICE_TYPE_WARNING = 'warning';

    /**
     * Constant for notice type warning with red left border
     */
    const NOTICE_TYPE_ERROR = 'error';

    /**
     * Constant for notice type warning with green left border
     */
    const NOTICE_TYPE_SUCCESS = 'success';

    /**
     * Constant for notice id default prefix
     */
    const DEFAULT_PREFIX = 'dup-notice-';

    /**
     * Constant for addition notice id prefix in case it's a global notice
     */
    const GLOBAL_PREFIX = 'global-';

    /**
     * The wp-options key in which the notices are stored
     */
    const DISMISSED_NOTICES_OPTKEY = 'duplicator_dismissed_admin_notices';

    /**
     * Notices.
     *
     * @var array
     */
    private static $notices = array();

    /**
     * Init.
     *
     * @return void
     */
    public static function init()
    {
        static::hooks();
    }

    /**
     * Hooks.
     *
     * @return void
     */
    public static function hooks()
    {
        add_action('admin_notices', array(__CLASS__, 'display'), PHP_INT_MAX);
        add_action('wp_ajax_dup_notice_dismiss', array(__CLASS__, 'dismissAjax'));
    }

    /**
     * Enqueue assets.
     *
     * @return void
     */
    private static function enqueues()
    {
        wp_enqueue_script(
            'dup-admin-notices',
            DUPLICATOR_PLUGIN_URL . "assets/js/notifications/notices.js",
            array('jquery'),
            DUPLICATOR_VERSION,
            true
        );

        wp_localize_script(
            'dup-admin-notices',
            'dup_admin_notices',
            array(
                'ajax_url' => admin_url('admin-ajax.php'),
                'nonce'    => wp_create_nonce('duplicator-admin-notice'),
            )
        );
    }

    /**
     * Display the notices.
     *
     * @return void
     */
    public static function display()
    {

        $dismissed_notices = get_user_meta(get_current_user_id(), self::DISMISSED_NOTICES_OPTKEY, true);
        $dismissed_notices = is_array($dismissed_notices) ? $dismissed_notices : array();
        $dismissed_notices = array_merge($dismissed_notices, (array)get_option(self::DISMISSED_NOTICES_OPTKEY, array()));

        foreach (self::$notices as $slug => $notice) {
            if (isset($dismissed_notices[$slug])) {
                unset(self::$notices[$slug]);
            }
        }

        $output = implode('', self::$notices);

        echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

        // Enqueue script only when it's needed.
        if (strpos($output, 'is-dismissible') !== false) {
            self::enqueues();
        }
    }

    /**
     * Add notice to the registry.
     *
     * @param string $message Message to display.
     * @param string $slug    Unique slug identifying the notice
     * @param string $type    Type of the notice. Can be [ '' (default) | 'info' | 'error' | 'success' | 'warning' ].
     * @param array  $args    The array of additional arguments. Please see the $defaults array below.
     *
     * @return void
     */
    public static function add($message, $slug, $type = '', $args = array())
    {
        $defaults = array(
            'dismiss' => self::DISMISS_NONE, // Dismissible level: one of the self::DISMISS_* const. By default notice is not dismissible.
            'autop'   => true,               // `false` if not needed to pass message through wpautop().
            'class'   => ''                 // Additional CSS class.
        );

        $args    = wp_parse_args($args, $defaults);
        $dismiss = (int)$args['dismiss'];
        $classes = array();

        if (!empty($type)) {
            $classes[] = 'notice-' . esc_attr(sanitize_key($type));
        }

        if (!empty($args['class'])) {
            $classes[] = esc_attr(sanitize_key($args['class']));
        }

        if ($dismiss > self::DISMISS_NONE) {
            $classes[] = 'is-dismissible';
        }

        $id      = $dismiss === self::DISMISS_GLOBAL ? self::DEFAULT_PREFIX . self::GLOBAL_PREFIX . $slug : self::DEFAULT_PREFIX . $slug;
        $message = $args['autop'] ? wpautop($message) : $message;
        $notice  = sprintf(
            '<div class="notice dup-notice %s" id="%s">%s</div>',
            esc_attr(implode(' ', $classes)),
            esc_attr($id),
            $message
        );

        self::$notices[$slug] = $notice;
    }

    /**
     * Add multistep notice.
     *
     * @param array  $steps Array of info for each step.
     * @param string $slug  Unique slug identifying the notice
     * @param string $type  Type of the notice. Can be [ '' (default) | 'info' | 'error' | 'success' | 'warning' ].
     * @param array  $args  Array of additional arguments. Details in the self::add() method.
     *
     * @return void
     */
    public static function addMultistep($steps, $slug, $type = '', $args = array())
    {
        $content = '<div class="dup-multi-notice">';
        foreach ($steps as $i => $step) {
            $hide     = $i === 0 ? '' : ' style="display: none;"';
            $content .= '<div class="dup-multi-notice-step dup-multi-notice-step-' . $i . '"' . $hide . '>';

            $content .= $step['message'];
            $content .= "<p>";
            foreach ($step["links"] as $link) {
                $url     = isset($link['url']) ? $link['url'] : "#";
                $target  = isset($link['url']) ? 'target="_blank"' : '';
                $switch  = isset($link['switch']) ? ' data-step="' . $link['switch'] . '"' : '';
                $dismiss = isset($link['dismiss']) && $link['dismiss'] ? ' class="dup-notice-dismiss"' : '';

                $content .= '<a href="' . $url . '"' . $dismiss . $switch . $target . '>' . $link['text'] . '</a><br>';
            }
            $content .= "</p>";
            $content .= "</div>";
        }
        $content .= "</div>";

        self::add($content, $slug, $type, $args);
    }

    /**
     * Add info notice.
     *
     * @param string $message Message to display.
     * @param string $slug    Unique slug identifying the notice
     * @param array  $args    Array of additional arguments. Details in the self::add() method.
     *
     * @return void
     */
    public static function info($message, $slug, $args = array())
    {

        self::add($message, $slug, self::NOTICE_TYPE_INFO, $args);
    }

    /**
     * Add error notice.
     *
     * @param string $message Message to display.
     * @param string $slug    Unique slug identifying the notice
     * @param array  $args    Array of additional arguments. Details in the self::add() method.
     *
     * @return void
     */
    public static function error($message, $slug, $args = array())
    {

        self::add($message, $slug, self::NOTICE_TYPE_ERROR, $args);
    }

    /**
     * Add success notice.
     *
     * @param string $message Message to display.
     * @param string $slug    Unique slug identifying the notice
     * @param array  $args    Array of additional arguments. Details in the self::add() method.
     *
     * @return void
     */
    public static function success($message, $slug, $args = array())
    {

        self::add($message, $slug, self::NOTICE_TYPE_SUCCESS, $args);
    }

    /**
     * Add warning notice.
     *
     * @param string $message Message to display.
     * @param string $slug    Unique slug identifying the notice
     * @param array  $args    Array of additional arguments. Details in the self::add() method.
     *
     * @return void
     */
    public static function warning($message, $slug, $args = array())
    {

        self::add($message, $slug, self::NOTICE_TYPE_WARNING, $args);
    }

    /**
     * AJAX routine that updates dismissed notices meta data.
     *
     * @return void
     */
    public static function dismissAjax()
    {

        // Run a security check.
        check_ajax_referer('duplicator-admin-notice', 'nonce');

        // Sanitize POST data.
        $post = array_map('sanitize_key', wp_unslash($_POST));

        // Update notices meta data.
        if (strpos($post['id'], self::GLOBAL_PREFIX) !== false) {
            // Check for permissions.
            if (!current_user_can('manage_options')) {
                wp_send_json_error();
            }

            $notices = self::dismissGlobal($post['id']);
            $level   = self::DISMISS_GLOBAL;
        } else {
            $notices = self::dismissUser($post['id']);
            $level   = self::DISMISS_USER;
        }

        /**
         * Allows developers to apply additional logic to the dismissing notice process.
         * Executes after updating option or user meta (according to the notice level).
         *
         * @param string  $notice_id Notice ID (slug).
         * @param integer $level     Notice level.
         * @param array   $notices   Dismissed notices.
         */
        do_action('duplicator_admin_notice_dismiss_ajax', $post['id'], $level, $notices);

        wp_send_json_success(
            array(
                'id'      => $post['id'],
                'time'    => time(),
                'level'   => $level,
                'notices' => $notices
            )
        );
    }

    /**
     * AJAX sub-routine that updates dismissed notices option.
     *
     * @param string $id Notice Id.
     *
     * @return array Notices.
     */
    private static function dismissGlobal($id)
    {

        $id           = str_replace(self::GLOBAL_PREFIX, '', $id);
        $notices      = get_option(self::DISMISSED_NOTICES_OPTKEY, array());
        $notices[$id] = array(
            'time' => time()
        );

        update_option(self::DISMISSED_NOTICES_OPTKEY, $notices, true);

        return $notices;
    }

    /**
     *  AJAX sub-routine that updates dismissed notices user meta.
     *
     * @param string $id Notice Id.
     *
     * @return array Notices.
     */
    private static function dismissUser($id)
    {

        $user_id      = get_current_user_id();
        $notices      = get_user_meta($user_id, self::DISMISSED_NOTICES_OPTKEY, true);
        $notices      = !is_array($notices) ? array() : $notices;
        $notices[$id] = array(
            'time' => time()
        );

        update_user_meta($user_id, self::DISMISSED_NOTICES_OPTKEY, $notices);

        return $notices;
    }

    /**
     * Delete related option
     *
     * @return void
     */
    public static function deleteOption()
    {
        delete_option(self::DISMISSED_NOTICES_OPTKEY);
    }
}
                                                                                                                        Notifications/Notifications.php                                                                     0000644                 00000040137 15174703155 0012714 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

namespace Duplicator\Core\Notifications;

use DUP_LITE_Plugin_Upgrade;
use DUP_Settings;
use Duplicator\Ajax\ServicesNotifications;
use Duplicator\Core\Views\TplMng;

/**
 * Notifications.
 */
class Notifications
{
    /**
     * Source of notifications content.
     *
     * @var string
     */
    const SOURCE_URL = 'https://notifications.duplicator.com/dp-notifications.json';

    /**
     * WordPress option key containing notification data
     *
     * @var string
     */
    const DUPLICATOR_NOTIFICATIONS_OPT_KEY = 'duplicator_notifications';

    /**
     * WordPress option key containing notification data
     *
     * @var string
     */
    const DUPLICATOR_BEFORE_PACKAGES_HOOK = 'duplicator_before_packages_table_action';

    /**
     * Duplicator notifications dismiss nonce key
     *
     * @var string
     */
    const DUPLICATOR_NOTIFICATION_NONCE_KEY = 'duplicator-notification-dismiss';

    /**
     * Option value.
     *
     * @var bool|array
     */
    public static $option = false;

    /**
     * Initialize class.
     *
     * @return void
     */
    public static function init()
    {
        // Delete data even if notifications are disabled.
        add_action('deactivate_plugin', array(__CLASS__, 'delete'), 10, 2);

        if (!DUP_Settings::Get('amNotices')) {
            return;
        }

        // Add notification count to menu label.
        add_filter('duplicator_menu_label_duplicator', function ($label) {
            if (self::getCount() === 0) {
                return $label;
            }
            return $label . '<span class="awaiting-mod">' . self::getCount() . '</span>';
        });

        self::update();

        add_action(self::DUPLICATOR_BEFORE_PACKAGES_HOOK, array(__CLASS__, 'output'));

        $notificationsService = new ServicesNotifications();
        $notificationsService->init();
    }

    /**
     * Check if user has access and is enabled.
     *
     * @return bool
     */
    public static function hasAccess()
    {
        return current_user_can('manage_options');
    }

    /**
     * Get option value.
     *
     * @param bool $cache Reference property cache if available.
     *
     * @return array
     */
    public static function getOption($cache = true)
    {
        if (self::$option && $cache) {
            return self::$option;
        }

        $option = get_option(self::DUPLICATOR_NOTIFICATIONS_OPT_KEY, array());

        self::$option = array(
            'update'    => !empty($option['update']) ? (int)$option['update'] : 0,
            'feed'      => !empty($option['feed']) ? (array)$option['feed'] : array(),
            'events'    => !empty($option['events']) ? (array)$option['events'] : array(),
            'dismissed' => !empty($option['dismissed']) ? (array)$option['dismissed'] : array()
        );

        return self::$option;
    }

    /**
     * Fetch notifications from feed.
     *
     * @return array
     */
    public static function fetchFeed()
    {
        $response = wp_remote_get(
            self::SOURCE_URL,
            array(
                'timeout'    => 10,
                'user-agent' => self::getUserAgent(),
            )
        );

        if (is_wp_error($response)) {
            return array();
        }

        $body = wp_remote_retrieve_body($response);

        if (empty($body)) {
            return array();
        }

        return self::verify(json_decode($body, true));
    }

    /**
     * Verify notification data before it is saved.
     *
     * @param array $notifications Array of notifications items to verify.
     *
     * @return array
     */
    public static function verify($notifications)
    {
        $data = array();
        if (!is_array($notifications) || empty($notifications)) {
            return $data;
        }

        foreach ($notifications as $notification) {
            // Ignore if one of the conditional checks is true:
            //
            // 1. notification message is empty.
            // 2. license type does not match.
            // 3. notification is expired.
            // 4. notification has already been dismissed.
            // 5. notification existed before installing Duplicator.
            // (Prevents bombarding the user with notifications after activation).
            if (
                empty($notification['content']) ||
                !self::isLicenseTypeMatch($notification) ||
                self::isExpired($notification) ||
                self::isDismissed($notification) ||
                self::isExisted($notification)
            ) {
                continue;
            }

            $data[] = $notification;
        }

        return $data;
    }

    /**
     * Verify saved notification data for active notifications.
     *
     * @param array $notifications Array of notifications items to verify.
     *
     * @return array
     */
    public static function verifyActive($notifications)
    {
        if (!is_array($notifications) || empty($notifications)) {
            return array();
        }

        $current_timestamp = time();

        // Remove notifications that are not active.
        foreach ($notifications as $key => $notification) {
            if (
                (!empty($notification['start']) && $current_timestamp < strtotime($notification['start'])) ||
                (!empty($notification['end']) && $current_timestamp > strtotime($notification['end']))
            ) {
                unset($notifications[$key]);
            }
        }

        return $notifications;
    }

    /**
     * Get notification data.
     *
     * @return array
     */
    public static function get()
    {
        if (!self::hasAccess()) {
            return array();
        }

        $option = self::getOption();

        $feed   = !empty($option['feed']) ? self::verifyActive($option['feed']) : array();
        $events = !empty($option['events']) ? self::verifyActive($option['events']) : array();

        return array_merge($feed, $events);
    }

    /**
     * Get notification count.
     *
     * @return int
     */
    public static function getCount()
    {
        return count(self::get());
    }

    /**
     * Add a new Event Driven notification.
     *
     * @param array $notification Notification data.
     *
     * @return void
     */
    public static function add($notification)
    {
        if (!self::isValid($notification)) {
            return;
        }

        $option = self::getOption();

        // Notification ID already exists.
        if (!empty($option['events'][$notification['id']])) {
            return;
        }

        $notification = self::verify(array($notification));
        update_option(
            self::DUPLICATOR_NOTIFICATIONS_OPT_KEY,
            array(
                'update'    => $option['update'],
                'feed'      => $option['feed'],
                'events'    => array_merge($notification, $option['events']),
                'dismissed' => $option['dismissed'],
            )
        );
    }

    /**
     * Determine if notification data is valid.
     *
     * @param array $notification Notification data.
     *
     * @return bool
     */
    public static function isValid($notification)
    {
        if (empty($notification['id'])) {
            return false;
        }

        return count(self::verify(array($notification))) > 0;
    }

    /**
     * Determine if notification has already been dismissed.
     *
     * @param array $notification Notification data.
     *
     * @return bool
     */
    private static function isDismissed($notification)
    {
        $option = self::getOption();

        return !empty($option['dismissed']) && in_array($notification['id'], $option['dismissed']);
    }

    /**
     * Determine if license type is match.
     *
     * @param array $notification Notification data.
     *
     * @return bool
     */
    private static function isLicenseTypeMatch($notification)
    {
        // A specific license type is not required.
        $notification['type'] = (array)$notification['type'];
        if (empty($notification['type'])) {
            return false;
        }

        if (in_array('any', $notification['type'])) {
            return true;
        }

        return in_array(self::getLicenseType(), (array)$notification['type'], true);
    }

    /**
     * Determine if notification is expired.
     *
     * @param array $notification Notification data.
     *
     * @return bool
     */
    private static function isExpired($notification)
    {
        return !empty($notification['end']) && time() > strtotime($notification['end']);
    }

    /**
     * Determine if notification existed before installing Duplicator.
     *
     * @param array $notification Notification data.
     *
     * @return bool
     */
    private static function isExisted($notification)
    {
        $installInfo = DUP_LITE_Plugin_Upgrade::getInstallInfo();
        return (!empty($notification['start']) && $installInfo['time'] > strtotime($notification['start']));
    }

    /**
     * Update notification data from feed.
     *
     * @return void
     */
    public static function update()
    {
        $option = self::getOption();

        //Only update twice daily
        if ($option['update'] !== 0 && time() < $option['update'] + DAY_IN_SECONDS / 2) {
            return;
        }

        $data = array(
            'update'    => time(),
            'feed'      => self::fetchFeed(),
            'events'    => $option['events'],
            'dismissed' => $option['dismissed'],
        );

        /**
         * Allow changing notification data before it will be updated in database.
         *
         * @param array $data New notification data.
         */
        $data = (array)apply_filters('duplicator_admin_notifications_update_data', $data);

        update_option(self::DUPLICATOR_NOTIFICATIONS_OPT_KEY, $data);
    }

    /**
     * Remove notification data from database before a plugin is deactivated.
     *
     * @param string $plugin Path to the plugin file relative to the plugins directory.
     *
     * @return void
     */
    public static function delete($plugin)
    {
        $duplicator_plugins = array(
            'duplicator-lite/duplicator.php',
            'duplicator/duplicator.php',
        );

        if (!in_array($plugin, $duplicator_plugins, true)) {
            return;
        }

        delete_option(self::DUPLICATOR_NOTIFICATIONS_OPT_KEY);
    }

    /**
     * Enqueue assets on Form Overview admin page.
     *
     * @return void
     */
    public static function enqueues()
    {
        if (!self::getCount()) {
            return;
        }

        wp_enqueue_style(
            'dup-admin-notifications',
            DUPLICATOR_PLUGIN_URL . "assets/css/admin-notifications.css",
            array('dup-lity'),
            DUPLICATOR_VERSION
        );

        wp_enqueue_script(
            'dup-admin-notifications',
            DUPLICATOR_PLUGIN_URL . "assets/js/notifications/admin-notifications.js",
            array('jquery', 'dup-lity'),
            DUPLICATOR_VERSION,
            true
        );

        wp_localize_script(
            'dup-admin-notifications',
            'dup_admin_notifications',
            array(
                'ajax_url' => admin_url('admin-ajax.php'),
                'nonce'    => wp_create_nonce(self::DUPLICATOR_NOTIFICATION_NONCE_KEY),
            )
        );

        // Lity.
        wp_enqueue_style(
            'dup-lity',
            DUPLICATOR_PLUGIN_URL . 'assets/lib/lity/lity.min.css',
            array(),
            DUPLICATOR_VERSION
        );

        wp_enqueue_script(
            'dup-lity',
            DUPLICATOR_PLUGIN_URL . 'assets/lib/lity/lity.min.js',
            array('jquery'),
            DUPLICATOR_VERSION,
            true
        );
    }

    /**
     * Output notifications on Form Overview admin area.
     *
     * @return void
     */
    public static function output()
    {
        $notificationsData = self::get();

        if (empty($notificationsData)) {
            return;
        }


        $content_allowed_tags = array(
            'br'     => array(),
            'em'     => array(),
            'strong' => array(),
            'span'   => array(
                'style' => array()
            ),
            'p'      => array(
                'id'    => array(),
                'class' => array()
            ),
            'a'      => array(
                'href'   => array(),
                'target' => array(),
                'rel'    => array()
            )
        );

        $notifications = array();
        foreach ($notificationsData as $notificationData) {
            // Prepare required arguments.
            $notificationData = wp_parse_args(
                $notificationData,
                array(
                    'id'      => 0,
                    'title'   => '',
                    'content' => '',
                    'video'   => ''
                )
            );

            $title   = self::getComponentData($notificationData['title']);
            $content = self::getComponentData($notificationData['content']);

            if (!$title && !$content) {
                continue;
            }

            $notifications[] = array(
                'id'        => $notificationData['id'],
                'title'     => $title,
                'btns'      => self::getButtonsData($notificationData),
                'content'   => wp_kses(wpautop($content), $content_allowed_tags),
                'video_url' => wp_http_validate_url(self::getComponentData($notificationData['video'])),
            );
        }

        self::enqueues();
        TplMng::getInstance()->render(
            'parts/Notifications/main',
            array(
                'notifications' => $notifications
            )
        );
    }

    /**
     * Retrieve notification's buttons.
     *
     * @param array $notification Notification data.
     *
     * @return array
     */
    private static function getButtonsData($notification)
    {
        if (empty($notification['btn']) || !is_array($notification['btn'])) {
            return array();
        }

        $buttons = array();
        if (!empty($notification['btn']['main_text']) && !empty($notification['btn']['main_url'])) {
            $buttons[] = array(
                'type'   => 'primary',
                'text'   => $notification['btn']['main_text'],
                'url'    => self::prepareBtnUrl($notification['btn']['main_url']),
                'target' => '_blank'
            );
        }

        if (!empty($notification['btn']['alt_text']) && !empty($notification['btn']['alt_url'])) {
            $buttons[] = array(
                'type'   => 'secondary',
                'text'   => $notification['btn']['alt_text'],
                'url'    => self::prepareBtnUrl($notification['btn']['alt_url']),
                'target' => '_blank'
            );
        }

        return $buttons;
    }

    /**
     * Retrieve notification's component data by a license type.
     *
     * @param mixed $data Component data.
     *
     * @return false|mixed
     */
    private static function getComponentData($data)
    {
        if (empty($data['license'])) {
            return $data;
        }

        $license_type = self::getLicenseType();
        return !empty($data['license'][$license_type]) ? $data['license'][$license_type] : false;
    }

    /**
     * Retrieve the current installation license type (always lowercase).
     *
     * @return string
     */
    private static function getLicenseType()
    {
        return 'lite';
    }

    /**
     * Prepare button URL.
     *
     * @param string $btnUrl Button url.
     *
     * @return string
     */
    private static function prepareBtnUrl($btnUrl)
    {
        if (empty($btnUrl)) {
            return '';
        }

        $replace_tags = array(
            '{admin_url}' => admin_url()
        );

        return wp_http_validate_url(str_replace(array_keys($replace_tags), array_values($replace_tags), $btnUrl));
    }

    /**
     * User agent that will be used for the request
     *
     * @return string
     */
    private static function getUserAgent()
    {
        return 'WordPress/' . get_bloginfo('version') . '; ' . get_bloginfo('url') . '; Duplicator/Lite-' . DUPLICATOR_VERSION;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                 Notifications/NoticeBar.php                                                                         0000644                 00000004016 15174703155 0011745 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

namespace Duplicator\Core\Notifications;

use Duplicator\Core\Controllers\ControllersManager;
use Duplicator\Core\Views\TplMng;
use Duplicator\Libs\Snap\SnapWP;

/**
 * Admin/NoticeBar Education feature for Lite.
 */
class NoticeBar
{
    /**
     * Constant for the wp-options key handling the dismissed state
     */
    const NOTICE_BAR_DISMISSED_OPT_KEY = 'duplicator_notice_bar_dismissed';

    /**
     * Init.
     *
     * @return void
     */
    public static function init()
    {
        add_action('in_admin_header', array(__CLASS__, 'display'));
        add_action('wp_ajax_duplicator_notice_bar_dismiss', array(__CLASS__, 'dismissNoticeBar'));
    }

    /**
     * Notice bar display message.
     *
     * @return void
     */
    public static function display()
    {
        if (!ControllersManager::isDuplicatorPage()) {
            return;
        }

        //make sure it wasn't dismissed
        if (get_user_meta(get_current_user_id(), self::NOTICE_BAR_DISMISSED_OPT_KEY, true) != false) {
            return;
        }

        $utm_content = '';
        foreach (ControllersManager::getMenuLevels() as $key => $value) {
            if (strlen((string) $value) == 0) {
                continue;
            }
            $utm_content .= ucfirst($key) . ' ' . $value . ' ';
        }
        $utm_content = trim($utm_content);

        TplMng::getInstance()->render('/parts/notice-bar', array(
            'utm_content' => $utm_content
        ));
    }

    /**
     * Dismiss notice bar ajax action
     *
     * @return void
     */
    public static function dismissNoticeBar()
    {
        // Run a security check.
        check_ajax_referer('duplicator-notice-bar-dismiss', 'nonce');
        update_user_meta(get_current_user_id(), self::NOTICE_BAR_DISMISSED_OPT_KEY, true);
    }

    /**
     * Delete related option
     *
     * @return bool true on success, false on failure
     */
    public static function deleteOption()
    {
        return SnapWP::deleteUserMetaKey(self::NOTICE_BAR_DISMISSED_OPT_KEY);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  Notifications/Review.php                                                                            0000644                 00000017042 15174703155 0011343 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

namespace Duplicator\Core\Notifications;

use DUP_LITE_Plugin_Upgrade;
use DUP_Package;
use Duplicator\Core\MigrationMng;
use Duplicator\Core\Controllers\ControllersManager;

/**
 * Ask for some love.
 */
class Review
{
    /**
     * Constant for the review request admin notice slug
     */
    const REVIEW_REQUEST_NOTICE_SLUG = 'review_request';

    /**
     * Primary class constructor.
     *
     * @return void
     */
    public static function init()
    {

        // Admin notice requesting review.
        add_action('admin_init', array(__CLASS__, 'reviewRequest'));

        // Admin footer text.
        add_filter('admin_footer_text', array(__CLASS__, 'adminFooter'), 1, 2);

        // Admin footer version text.
        add_filter('update_footer', array(__CLASS__, 'adminFooterVersion'), 9999);
    }

    /**
     * Add admin notices as needed for reviews.
     *
     * @return void
     */
    public static function reviewRequest()
    {

        // Only consider showing the review request to admin users.
        if (!is_super_admin()) {
            return;
        }

        // Get dismissed notices.
        $notices = get_option(Notice::DISMISSED_NOTICES_OPTKEY, array());

        //has already been dismissed, don't show again
        if (isset($notices[self::REVIEW_REQUEST_NOTICE_SLUG])) {
            return;
        }

        self::reviewLite();
    }

    /**
     * Maybe show Lite review request.
     *
     * @return void
     */
    public static function reviewLite()
    {
        $display = false;

        // Fetch when plugin was initially installed.
        $installInfo      = DUP_LITE_Plugin_Upgrade::getInstallInfo();
        $numberOfPackages = DUP_Package::count_by_status(array(
            array('op' => '=' , 'status' => \DUP_PackageStatus::COMPLETE )
        ));

        // Display if plugin has been installed for at least 3 days and has a package installed
        if ((($installInfo['time'] + (DAY_IN_SECONDS * 3)) < time() && $numberOfPackages > 0)) {
            $display = true;
        }

        //Display if it's been 3 days after a successful migration
        $migrationTime = MigrationMng::getMigrationData('time');
        if (!$display && $migrationTime !== false && (($migrationTime + (DAY_IN_SECONDS * 3)) < time())) {
            $display = true;
        }

        if (!$display) {
            return;
        }

        Notice::addMultistep(
            array(
                array(
                    "message" => "<p>" . sprintf(__('Are you enjoying %s?', 'duplicator'), 'Duplicator') . "</p>",
                    "links"   => array(
                        array(
                            "text"   => __('Yes', 'duplicator'),
                            "switch" => 1
                        ),
                        array(
                            "text"   => __('Not really', 'duplicator'),
                            "switch" => 2
                        )
                    )
                ),
                array(
                    "message" => "<p>" .
                        __(
                            'That’s awesome! Could you please do me a BIG favor and give it a 5-star rating on ' .
                            'WordPress to help us spread the word and boost our motivation?',
                            'duplicator'
                        ) . "</p>" .
                        "<p>" . wp_kses(__('~ John Turner<br>President of Duplicator', 'duplicator'), array('br' => array())) . "</p>",
                    "links"   => array(
                        array(
                            "url"  => self::getReviewUrl(),
                            "text" => __('Ok, you deserve it', 'duplicator'),
                            "dismiss" => true
                        ),
                        array(
                            "text"    => __('Nope, maybe later', 'duplicator'),
                            "dismiss" => true
                        ),
                        array(
                            "text"    => __('I already did', 'duplicator'),
                            "dismiss" => true
                        )
                    )
                ),
                array(
                    "message" => "<p>" .
                        __(
                            'We\'re sorry to hear you aren\'t enjoying Duplicator. We would love a chance to improve. ' .
                            'Could you take a minute and let us know what we can do better?',
                            'duplicator'
                        ) . "</p>",
                    "links"   => array(
                        array(
                            "url"  => self::getFeedbackUrl(),
                            "text" => __('Give Feedback', 'duplicator'),
                            "dismiss" => true
                        ),
                        array(
                            "text"    => __('No thanks', 'duplicator'),
                            "dismiss" => true
                        )
                    )
                )
            ),
            self::REVIEW_REQUEST_NOTICE_SLUG,
            Notice::NOTICE_TYPE_INFO,
            array(
                'dismiss' => Notice::DISMISS_GLOBAL,
                'autop'   => false,
                'class'   => 'dup-review-notice',
            )
        );
    }

    /**
     * @return string The review url on wordpress.org
     */
    public static function getReviewUrl()
    {
        return "https://wordpress.org/support/plugin/duplicator/reviews/#new-post";
    }

    /**
     * @return string The snapcreek feedback url
     */
    public static function getFeedbackUrl()
    {
        return DUPLICATOR_BLOG_URL . "contact/";
    }

    /**
     * Updates admin footer text by adding Duplicator version
     *
     * @param string $defaultText Default WP footer text
     *
     * @return string Modified version text
     */
    public static function adminFooterVersion($defaultText)
    {
        if (!ControllersManager::isDuplicatorPage()) {
            return $defaultText;
        }

        $defaultText = sprintf(
            '%1$s | Duplicator %2$s',
            $defaultText,
            esc_html(DUPLICATOR_VERSION)
        );

        return $defaultText;
    }

    /**
     * When user is on a Duplicator related admin page, display footer text
     * that graciously asks them to rate us.
     *
     * @param string $text Footer text.
     *
     * @return string
     */
    public static function adminFooter($text)
    {
        //Show only on duplicator pages
        if (
            ! is_admin() ||
            empty($_REQUEST['page']) ||
            strpos($_REQUEST['page'], 'duplicator') === false
        ) {
            return false;
        }

        $text = sprintf(
            wp_kses( /* translators: $1$s - WPForms plugin name; $2$s - WP.org review link; $3$s - WP.org review link. */
                __(
                    'Please rate <strong>Duplicator</strong> ' .
                    '<a href="%1$s" target="_blank" rel="noopener noreferrer">&#9733;&#9733;&#9733;&#9733;&#9733;</a>' .
                    ' on <a href="%1$s" target="_blank" rel="noopener">WordPress.org</a> to help us spread the word. Thank you from the Duplicator team!',
                    'duplicator'
                ),
                array(
                    'a' => array(
                        'href'   => array(),
                        'target' => array(),
                        'rel'    => array(),
                    ),
                    'strong' => array()
                )
            ),
            self::getReviewUrl()
        );

        return $text;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              Bootstrap.php                                                                                       0000644                 00000062442 15174703155 0007252 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/**
 * Interface that collects the functions of initial duplicator Bootstrap
 *
 * @package   Duplicator
 * @copyright (c) 2022, Snap Creek LLC
 */

namespace Duplicator\Core;

use DUP_Constants;
use DUP_CTRL_Package;
use DUP_CTRL_Tools;
use DUP_CTRL_UI;
use DUP_Custom_Host_Manager;
use DUP_DB;
use DUP_LITE_Plugin_Upgrade;
use DUP_Log;
use DUP_Package;
use DUP_Settings;
use DUP_UI_Screen;
use Duplicator\Controllers\HelpPageController;
use Duplicator\Utils\Email\EmailSummaryBootstrap;
use Duplicator\Views\AdminNotices;
use DUP_Util;
use DUP_Web_Services;
use Duplicator\Ajax\ServicesDashboard;
use Duplicator\Ajax\ServicesEducation;
use Duplicator\Ajax\ServicesExtraPlugins;
use Duplicator\Ajax\ServicesTools;
use Duplicator\Controllers\AboutUsController;
use Duplicator\Controllers\EmailSummaryPreviewPageController;
use Duplicator\Controllers\WelcomeController;
use Duplicator\Core\Controllers\ControllersManager;
use Duplicator\Core\Notifications\Notice;
use Duplicator\Core\Notifications\NoticeBar;
use Duplicator\Core\Notifications\Notifications;
use Duplicator\Core\Notifications\Review;
use Duplicator\Core\Views\TplMng;
use Duplicator\Utils\CronUtils;
use Duplicator\Utils\ExtraPlugins\CrossPromotion;
use Duplicator\Utils\LinkManager;
use Duplicator\Views\DashboardWidget;
use Duplicator\Views\EducationElements;
use Duplicator\Utils\UsageStatistics\StatsBootstrap;

class Bootstrap
{
    /**
     * Init plugin
     *
     * @return void
     */
    public static function init()
    {
        add_action('init', array(__CLASS__, 'hookWpInit'));

        if (is_admin()) {
            add_action('plugins_loaded', array(__CLASS__, 'update'));
            add_action('plugins_loaded', array(__CLASS__, 'wpfrontIntegrate'));
            add_action('init', array(__CLASS__, 'loadTextdomain'));

            /* ========================================================
            * ACTIVATE/DEACTIVE/UPDATE HOOKS
            * =====================================================  */
            register_activation_hook(DUPLICATOR_LITE_FILE, array('DUP_LITE_Plugin_Upgrade', 'onActivationAction'));
            Unistall::registerHooks();
        }

        CronUtils::init();
        StatsBootstrap::init();
        EmailSummaryBootstrap::init();
    }

    /**
     * Method called on wordpress hook init action
     *
     * @return void
     */
    public static function hookWpInit()
    {
        if (is_admin()) {
            $GLOBALS['CTRLS_DUP_CTRL_UI']      = new DUP_CTRL_UI();
            $GLOBALS['CTRLS_DUP_CTRL_Tools']   = new DUP_CTRL_Tools();
            $GLOBALS['CTRLS_DUP_CTRL_Package'] = new DUP_CTRL_Package();

            if (is_multisite()) {
                add_action('network_admin_menu', array(__CLASS__, 'menuInit'));
                add_filter('network_admin_plugin_action_links', array(__CLASS__, 'manageLink'), 10, 2);
                add_filter('network_admin_plugin_row_meta', array(__CLASS__, 'metaLinks'), 10, 2);
            } else {
                add_action('admin_menu', array(__CLASS__, 'menuInit'));
                add_filter('plugin_action_links', array(__CLASS__, 'manageLink'), 10, 2);
                add_filter('plugin_row_meta', array(__CLASS__, 'metaLinks'), 10, 2);
            }

            add_action('admin_init', array(__CLASS__, 'adminInit'));
            add_action('in_admin_footer', array(__CLASS__, 'pluginFooter' ));
            add_action('admin_footer', array(__CLASS__, 'adjustProMenuItemClass'));
            add_action('admin_enqueue_scripts', array(__CLASS__, 'adminEqueueScripts'));

            add_action('wp_ajax_duplicator_active_package_info', 'duplicator_active_package_info');
            add_action('wp_ajax_duplicator_package_scan', 'duplicator_package_scan');
            add_action('wp_ajax_duplicator_package_build', 'duplicator_package_build');
            add_action('wp_ajax_duplicator_package_delete', 'duplicator_package_delete');
            add_action('wp_ajax_duplicator_duparchive_package_build', 'duplicator_duparchive_package_build');

            add_filter('admin_body_class', array(__CLASS__, 'addBodyClass'));

            //Init Class
            DUP_Custom_Host_Manager::getInstance()->init();
            DUP_Settings::init();
            DUP_Log::Init();
            DUP_Util::init();
            DUP_DB::init();
            MigrationMng::init();
            Notice::init();
            NoticeBar::init();
            Review::init();
            AdminNotices::init();
            DUP_Web_Services::init();
            WelcomeController::init();
            DashboardWidget::init();
            EducationElements::init();
            Notifications::init();
            EmailSummaryPreviewPageController::init();
            HelpPageController::init();
            CrossPromotion::init();
            $dashboardService = new ServicesDashboard();
            $dashboardService->init();
            $extraPlugin = new ServicesExtraPlugins();
            $extraPlugin->init();
            $educationService = new ServicesEducation();
            $educationService->init();
            $toolsServices = new ServicesTools();
            $toolsServices->init();
        }
    }

    /**
     * Return admin body classes
     *
     * @param string $classes classes
     *
     * @return string
     */
    public static function addBodyClass($classes)
    {
        if (ControllersManager::isDuplicatorPage()) {
            $classes .= ' duplicator-pages';
        }
        return $classes;
    }

    /**
     * Hooked into `plugins_loaded`.  Routines used to update the plugin
     *
     * @return null
     */
    public static function update()
    {
        if (DUPLICATOR_VERSION != get_option(DUP_LITE_Plugin_Upgrade::DUP_VERSION_OPT_KEY)) {
            DUP_LITE_Plugin_Upgrade::onActivationAction();
            // $snapShotDirPerm = substr(sprintf("%o", fileperms(DUP_Settings::getSsdirPath())),-4);
        }
        load_plugin_textdomain('duplicator');
    }

    /**
     * Load text domain for translation
     *
     * @return void
     */
    public static function loadTextdomain()
    {
        load_plugin_textdomain('duplicator', false, false);
    }

    /**
     * User role editor integration
     *
     * @return void
     */
    public static function wpfrontIntegrate()
    {
        if (DUP_Settings::Get('wpfront_integrate')) {
            do_action('wpfront_user_role_editor_duplicator_init', array('export', 'manage_options', 'read'));
        }
    }

    /**
     * Hooked into `admin_init`.  Init routines for all admin pages
     *
     * @return void
     */
    public static function adminInit()
    {
        add_action('in_admin_header', array('Duplicator\\Views\\ViewHelper', 'adminLogoHeader'), 100);

        /* CSS */
        wp_register_style('dup-jquery-ui', DUPLICATOR_PLUGIN_URL . 'assets/css/jquery-ui.css', null, "1.14.1");
        wp_register_style('dup-font-awesome', DUPLICATOR_PLUGIN_URL . 'assets/css/font-awesome/css/all.min.css', [], '6.4.2');
        wp_register_style('dup-plugin-global-style', DUPLICATOR_PLUGIN_URL . 'assets/css/global_admin_style.css', null, DUPLICATOR_VERSION);
        wp_register_style('dup-plugin-style', DUPLICATOR_PLUGIN_URL . 'assets/css/style.css', array('dup-plugin-global-style'), DUPLICATOR_VERSION);

        wp_register_style('dup-jquery-qtip', DUPLICATOR_PLUGIN_URL . 'assets/js/jquery.qtip/jquery.qtip.min.css', null, '2.2.1');
        wp_register_style('dup-parsley-style', DUPLICATOR_PLUGIN_URL . 'assets/css/parsley.css', null, '2.3.5');
        /* JS */
        wp_register_script('dup-handlebars', DUPLICATOR_PLUGIN_URL . 'assets/js/handlebars.min.js', array('jquery'), '4.0.10');
        wp_register_script('dup-parsley', DUPLICATOR_PLUGIN_URL . 'assets/js/parsley.min.js', array('jquery'), '1.1.18');
        wp_register_script('dup-jquery-qtip', DUPLICATOR_PLUGIN_URL . 'assets/js/jquery.qtip/jquery.qtip.min.js', array('jquery'), '2.2.1');

        add_action('admin_head', [DUP_UI_Screen::class, 'getCustomCss']);
        // Clean tmp folder
        DUP_Package::not_active_files_tmp_cleanup();

        $unhook_third_party_js  = DUP_Settings::Get('unhook_third_party_js');
        $unhook_third_party_css = DUP_Settings::Get('unhook_third_party_css');
        if ($unhook_third_party_js || $unhook_third_party_css) {
            add_action('admin_enqueue_scripts', array(__CLASS__, 'unhookThirdPartyAssets'), 99999, 1);
        }
    }

    /**
     * Hooked into `admin_menu`.  Loads all of the wp left nav admin menus for Duplicator
     *
     * @return void
     */
    public static function menuInit()
    {
        $menuLabel = apply_filters('duplicator_menu_label_duplicator', 'Duplicator');
        //SVG Icon: See https://websemantics.uk/tools/image-to-data-uri-converter/
        $hook_prefix = add_menu_page('Duplicator Plugin', $menuLabel, 'export', 'duplicator', null, DUP_Constants::ICON_SVG);
        add_action('admin_print_scripts-' . $hook_prefix, array(__CLASS__, 'scripts'));
        add_action('admin_print_styles-' . $hook_prefix, array(__CLASS__, 'styles'));

        //Submenus are displayed in the same order they have in the array
        $subMenuItems = self::getSubmenuItems();
        foreach ($subMenuItems as $k => $subMenuItem) {
            $pageTitle = apply_filters('duplicator_page_title_' . $subMenuItem['menu_slug'], $subMenuItem['page_title']);
            $menuLabel = apply_filters('duplicator_menu_label_' . $subMenuItem['menu_slug'], $subMenuItem['menu_title']);

            $subMenuItems[$k]['hook_prefix'] = add_submenu_page(
                $subMenuItem['parent_slug'],
                $pageTitle,
                $menuLabel,
                $subMenuItem['capability'],
                $subMenuItem['menu_slug'],
                $subMenuItem['callback'],
                $k
            );
            add_action('admin_print_scripts-' . $subMenuItems[$k]['hook_prefix'], array(__CLASS__, 'scripts'));

            if (isset($subMenuItem['enqueue_style_callback'])) {
                add_action('admin_print_styles-' . $subMenuItems[$k]['hook_prefix'], $subMenuItem['enqueue_style_callback']);
            }
            add_action('admin_print_styles-' . $subMenuItems[$k]['hook_prefix'], array(__CLASS__, 'styles'));
        }
    }

    /**
     * Submenu datas
     *
     * @return array[]
     */
    protected static function getSubmenuItems()
    {
        $proTitle   = '<span id="dup-link-upgrade-highlight">' . __('Upgrade to Pro', 'duplicator') . '</span>';
        $dupMenuNew = '<span class="dup-menu-new">&nbsp;' . __('NEW!', 'duplicator') . '</span>';
        return array(
            array(
                'parent_slug' => 'duplicator',
                'page_title'  => __('Backups', 'duplicator'),
                'menu_title'  => __('Backups', 'duplicator'),
                'capability'  => 'export',
                'menu_slug'   => ControllersManager::MAIN_MENU_SLUG,
                'callback'    => function () {
                    include(DUPLICATOR_PLUGIN_PATH . 'views/packages/controller.php');
                }
            ),
            array(
                'parent_slug'            => 'duplicator',
                'page_title'             => __('Import Backups', 'duplicator'),
                'menu_title'             => __('Import Backups', 'duplicator'),
                'capability'             => 'export',
                'menu_slug'              => ControllersManager::IMPORT_SUBMENU_SLUG,
                'callback'               => function () {
                    TplMng::getInstance()->render('mocks/import/import');
                },
                'enqueue_style_callback' => array(__CLASS__, 'mocksStyles')
            ),
            array(
                'parent_slug'            => 'duplicator',
                'page_title'             => __('Schedule Backups', 'duplicator'),
                'menu_title'             => __('Schedule Backups', 'duplicator') . $dupMenuNew,
                'capability'             => 'export',
                'menu_slug'              => ControllersManager::SCHEDULES_SUBMENU_SLUG,
                'callback'               => function () {
                    TplMng::getInstance()->render('mocks/schedule/schedules');
                },
                'enqueue_style_callback' => array(__CLASS__, 'mocksStyles')
            ),
            array(
                'parent_slug'            => 'duplicator',
                'page_title'             => __('Storage', 'duplicator'),
                'menu_title'             => '<span class="dup-storages-menu-highlight">' . __('Storage', 'duplicator') . '</span>',
                'capability'             => 'export',
                'menu_slug'              => ControllersManager::STORAGE_SUBMENU_SLUG,
                'callback'               => array('Duplicator\\Controllers\\StorageController', 'render'),
                'enqueue_style_callback' => array(__CLASS__, 'mocksStyles')
            ),
            array(
                'parent_slug'            => 'duplicator',
                'page_title'             => __('Staging', 'duplicator'),
                'menu_title'             => __('Staging', 'duplicator'),
                'capability'             => 'export',
                'menu_slug'              => ControllersManager::STAGING_SUBMENU_SLUG,
                'callback'               => function () {
                    TplMng::getInstance()->render('mocks/staging/staging');
                },
                'enqueue_style_callback' => array(__CLASS__, 'mocksStyles')
            ),
            array(
                'parent_slug'            => 'duplicator',
                'page_title'             => __('Tools', 'duplicator'),
                'menu_title'             => __('Tools', 'duplicator'),
                'capability'             => 'manage_options',
                'menu_slug'              => ControllersManager::TOOLS_SUBMENU_SLUG,
                'callback'               => function () {
                    include(DUPLICATOR_PLUGIN_PATH . 'views/tools/controller.php');
                },
                'enqueue_style_callback' => function () {
                    AboutUsController::enqueues();
                    self::mocksStyles();
                }
            ),
            array(
                'parent_slug'            => 'duplicator',
                'page_title'             => __('Settings', 'duplicator'),
                'menu_title'             => __('Settings', 'duplicator'),
                'capability'             => 'manage_options',
                'menu_slug'              => ControllersManager::SETTINGS_SUBMENU_SLUG,
                'callback'               => function () {
                    include(DUPLICATOR_PLUGIN_PATH . 'views/settings/controller.php');
                }
            ),
            array(
                'parent_slug'            => 'duplicator',
                'page_title'             => __('About Duplicator', 'duplicator'),
                'menu_title'             => __('About Us', 'duplicator'),
                'capability'             => 'manage_options',
                'menu_slug'              => ControllersManager::ABOUT_US_SUBMENU_SLUG,
                'callback'               => array('Duplicator\\Controllers\\AboutUsController', 'render'),
                'enqueue_style_callback' => array('Duplicator\\Controllers\\AboutUsController', 'enqueues')
            ),
            array(
                'parent_slug' => 'duplicator',
                'page_title'  => $proTitle,
                'menu_title'  => $proTitle,
                'capability'  => 'manage_options',
                'menu_slug'   => LinkManager::getCampaignUrl('admin-menu', 'Upgrade to Pro'),
                'callback'    => null,
            )
        );
    }

    /**
     * Hooked into `admin_enqueue_scripts`.  Init routines for all admin pages
     *
     * @access global
     * @return null
     */
    public static function adminEqueueScripts()
    {
        wp_enqueue_script('dup-global-script', DUPLICATOR_PLUGIN_URL . 'assets/js/global-admin-script.js', array('jquery'), DUPLICATOR_VERSION, true);
        wp_localize_script(
            'dup-global-script',
            'dup_global_script_data',
            array(
                'nonce_admin_notice_to_dismiss'              => wp_create_nonce('duplicator_admin_notice_to_dismiss'),
                'nonce_settings_callout_to_dismiss'          => wp_create_nonce('duplicator_settings_callout_cta_dismiss'),
                'nonce_packages_bottom_bar_dismiss'          => wp_create_nonce('duplicator_packages_bottom_bar_dismiss'),
                'nonce_email_subscribe'                      => wp_create_nonce('duplicator_email_subscribe'),
                'nonce_dashboard_widged_info'                => wp_create_nonce("duplicator_dashboad_widget_info"),
                'nonce_dashboard_widged_dismiss_recommended' => wp_create_nonce("duplicator_dashboad_widget_dismiss_recommended"),
                'ajaxurl'                                    => admin_url('admin-ajax.php')
            )
        );
        wp_localize_script(
            'dup-global-script',
            'l10nDupGlobalScript',
            array(
                'subscribe'   => esc_html__('Subscribe', 'duplicator'),
                'subscribed'  => esc_html__('Subscribed &#10003', 'duplicator'),
                'subscribing' => esc_html__('Subscribing...', 'duplicator'),
                'fail'        => esc_html__('Failed &#10007', 'duplicator'),
                'emailFail'   => esc_html__('Email subscription failed with message: ', 'duplicator'),
            )
        );

        wp_enqueue_script('dup-one-click-upgrade-script', DUPLICATOR_PLUGIN_URL . 'assets/js/one-click-upgrade.js', array('jquery'), DUPLICATOR_VERSION, true);
        wp_localize_script(
            'dup-one-click-upgrade-script',
            'dup_one_click_upgrade_script_data',
            array(
                'nonce_generate_connect_oth' => wp_create_nonce('duplicator_generate_connect_oth'),
                'ajaxurl'                   => admin_url('admin-ajax.php'),
                'fail_notice_title'         => __('Failed to connect to Duplicator Pro.', 'duplicator'),
                'fail_notice_message_label' => __('Message: ', 'duplicator'),
                'fail_notice_suggestion'    => __('Please try again or contact support if the issue persists.', 'duplicator'),
            )
        );

        wp_enqueue_script('dup-dynamic-help', DUPLICATOR_PLUGIN_URL . 'assets/js/dynamic-help.js', array('jquery'), DUPLICATOR_VERSION, true);
        wp_localize_script(
            'dup-dynamic-help',
            'l10nDupDynamicHelp',
            array(
                'failMsg' => esc_html__('Failed to load help content!', 'duplicator')
            )
        );

        wp_enqueue_script('dup-duplicator-tooltip', DUPLICATOR_PLUGIN_URL . 'assets/js/duplicator-tooltip.js', array('jquery'), DUPLICATOR_VERSION, true);
        wp_localize_script(
            'dup-duplicator-tooltip',
            'l10nDupTooltip',
            array(
                'copy'       => esc_html__('Copy to clipboard', 'duplicator'),
                'copied'     => esc_html__('copied to clipboard', 'duplicator'),
                'copyUnable' => esc_html__('Unable to copy', 'duplicator')
            )
        );

        wp_enqueue_style('dup-plugin-global-style');
    }

    /**
     * Add the PRO badge to left sidebar menu item.
     *
     * @return void
     */
    public static function adjustProMenuItemClass()
    {
        //Add to footer so it's applied on hovered item too
        ?>
            <script>jQuery(function($) {
                $('#dup-link-upgrade-highlight').parent().attr('target','_blank');
                $('#dup-link-upgrade-highlight').closest('li').addClass('dup-submenu-upgrade-highlight')
            });
            </script>
            <style>
                .dup-submenu-upgrade-highlight,
                .dup-submenu-upgrade-highlight a,
                .dup-submenu-upgrade-highlight a span#dup-link-upgrade-highlight {
                    background-color: #1da867!important;
                    color: #fff!important;
                    border-color: #fff!important;
                    font-weight: 600!important;
                }

                .dup-storages-menu-highlight {
                    color: #27d584;
                }

                #adminmenu .dup-menu-new {
                    color: #f18200;
                    vertical-align: super;
                    font-size: 9px;
                    font-weight: 600;
                    padding-left: 2px;
                }
            </style>
        <?php
    }

    /**
     * Add the plugin footer
     *
     * @return void
     */
    public static function pluginFooter()
    {
        if (!ControllersManager::isDuplicatorPage()) {
            return;
        }
        TplMng::getInstance()->render('parts/plugin-footer');
    }

    /**
     * Loads all required javascript libs/source for DupPro
     *
     * @return void
     */
    public static function scripts()
    {
        wp_enqueue_script('jquery');
        wp_enqueue_script('jquery-ui-core');
        wp_enqueue_script('jquery-ui-progressbar');
        wp_enqueue_script('dup-parsley');
        wp_enqueue_script('dup-jquery-qtip');
    }

    /**
     * Loads all CSS style libs/source for DupPro
     *
     * @return void
     */
    public static function styles()
    {
        wp_enqueue_style('dup-jquery-ui');
        wp_enqueue_style('dup-font-awesome');
        wp_enqueue_style('dup-plugin-style');
        wp_enqueue_style('dup-jquery-qtip');
    }

    /**
     * Enqueue mock related styles
     *
     * @return void
     */
    public static function mocksStyles()
    {
        wp_enqueue_style(
            'dup-mocks-styles',
            DUPLICATOR_PLUGIN_URL . 'assets/css/mocks.css',
            array(),
            DUPLICATOR_VERSION
        );
    }

    /**
     * Adds the manage link in the plugins list
     *
     * @param string[] $links links
     * @param string   $file  file
     *
     * @return string The manage link in the plugins list
     */
    public static function manageLink($links, $file)
    {
        static $this_plugin;
        if (!$this_plugin) {
            $this_plugin = plugin_basename(DUPLICATOR_LITE_FILE);
        }

        if ($file == $this_plugin) {
            /*
              $settings_link = '<a href="admin.php?page=duplicator">' . esc_html__("Manage", 'duplicator') . '</a>';
              array_unshift($links, $settings_link);
             */
            $upgrade_link = '<a style="color: #1da867;" class="dup-plugins-list-pro-upgrade" href="' .
                esc_url(LinkManager::getCampaignUrl('plugin-actions-link')) . '" target="_blank">' .
                '<strong style="display: inline;">' .
                esc_html__("Upgrade to Pro", 'duplicator') .
                '</strong></a>';
            array_unshift($links, $upgrade_link);
        }
        return $links;
    }

    /**
     * Adds links to the plugins manager page
     *
     * @param string[] $links links
     * @param string   $file  file
     *
     * @return string The meta help link data for the plugins manager
     */
    public static function metaLinks($links, $file)
    {
        $plugin = plugin_basename(DUPLICATOR_LITE_FILE);
        // create link
        if ($file == $plugin) {
            $links[] = '<a href="admin.php?page=duplicator" title="' . esc_attr__('Manage Backups', 'duplicator') . '" style="">' .
                esc_html__('Manage', 'duplicator') .
                '</a>';
            return $links;
        }
        return $links;
    }

    /**
     * Remove all external styles and scripts coming from other plugins
     * which may cause compatibility issue, especially with React
     *
     * @param string $hook hook
     *
     * @return void
     */
    public static function unhookThirdPartyAssets($hook)
    {
        /*
          $hook values in duplicator admin pages:
          toplevel_page_duplicator
          duplicator_page_duplicator-tools
          duplicator_page_duplicator-settings
          duplicator_page_duplicator-gopro
         */
        if (strpos($hook, 'duplicator') !== false && strpos($hook, 'duplicator-pro') === false) {
            $unhook_third_party_js  = DUP_Settings::Get('unhook_third_party_js');
            $unhook_third_party_css = DUP_Settings::Get('unhook_third_party_css');
            $assets                 = array();
            if ($unhook_third_party_css) {
                $assets['styles'] = wp_styles();
            }
            if ($unhook_third_party_js) {
                $assets['scripts'] = wp_scripts();
            }
            foreach ($assets as $type => $asset) {
                foreach ($asset->registered as $handle => $dep) {
                    $src = $dep->src;
                    // test if the src is coming from /wp-admin/ or /wp-includes/ or /wp-fsqm-pro/.
                    if (
                        is_string($src) && // For some built-ins, $src is true|false
                        strpos($src, 'wp-admin') === false &&
                        strpos($src, 'wp-include') === false &&
                        // things below are specific to your plugin, so change them
                        strpos($src, 'duplicator') === false &&
                        strpos($src, 'woocommerce') === false &&
                        strpos($src, 'jetpack') === false &&
                        strpos($src, 'debug-bar') === false
                    ) {
                        'scripts' === $type ? wp_dequeue_script($handle) : wp_dequeue_style($handle);
                    }
                }
            }
        }
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              