<?PHP

#
#   FILE:  SPT--SPTUser.php
#
#   Part of the Collection Workflow Integration System (CWIS)
#   Copyright 2004-2013 Edward Almasy and Internet Scout Research Group
#   http://scout.wisc.edu/cwis/
#

class SPTUser extends CWUser
{

    # ---- PUBLIC INTERFACE --------------------------------------------------

    /**
    * Get/generate a cryptographic keypair for user login.
    * CWIS can use RSA encryption on the password field of login
    * forms.  This function gets the most recently generated
    * keypair, clearing out keys older than 48 hours, and
    * re-generating a new key if the most recent one is older than 24
    * hours.
    * @return openssl format keypair
    */
    public static function GetCryptKey()
    {
        $DB = new Database();

        # Clear all keys more than two days old
        $DB->Query("DELETE FROM UsedLoginTokens WHERE NOW()-KeyCTime > 172800");

        $DB->Query("LOCK TABLES LoginKeys WRITE");
        $DB->Query("DELETE FROM LoginKeys WHERE NOW() - CreationTime > 172800");

        # Get the most recently generated key
        $DB->Query("SELECT NOW()-CreationTime as Age,"
                   ."KeyPair FROM LoginKeys "
                   ."ORDER BY Age ASC LIMIT 1");
        $Row = $DB->FetchRow();

        # If there is no key in the database, or the key is too old
        if ( ($Row===FALSE) || ($Row["Age"]>=86400) )
        {
            # Generate a new OpenSSL format keypair
            $KeyPair = openssl_pkey_new(
                array(
                    'private_key_bits' => 512, # Make this a Sysadmin pref later?
                    'private_key_type' => OPENSSL_KEYTYPE_RSA ));

            # Serialize it for storage
            openssl_pkey_export($KeyPair, $KeyPairDBFormat);

            # And stick it into the database
            $DB->Query("INSERT INTO LoginKeys "
                       ."(KeyPair, CreationTime) VALUES ("
                       ."\"".addslashes($KeyPairDBFormat)."\","
                       ."NOW())");
        }
        else
        {
            # If we do have a current key in the database,
            #  Convert it to openssl format for usage
            $KeyPair = openssl_pkey_get_private( $Row["KeyPair"] );
        }
        $DB->Query("UNLOCK TABLES");

        return $KeyPair;
    }

    /**
    * Extract the modulus and exponent of the public key from an OpenSSL format
    * keypair to send in login forms.
    * @param resource $KeyPair An openssl format keypair as returned by
    *   SPTUser::GetCryptKey().
    * @return Associative array containing "Modulus" and "Exponent" key parameters
    */
    public static function ExtractPubKeyParameters($KeyPair)
    {
        # Export the keypair as an ASCII signing request (which contains the data we want)
        openssl_csr_export(openssl_csr_new(array(), $KeyPair), $Export, FALSE);

        $Modulus  = "";
        $Exponent = "";

        // @codingStandardsIgnoreStart
        $Patterns = array(
            '/Modulus \([0-9]+ bit\):(.*)Exponent: [0-9]+ \(0x([0-9a-f]+)\)/ms',
            '/Public-Key: \([0-9]+ bit\).*Modulus:(.*)Exponent: [0-9]+ \(0x([0-9a-f]+)\)/ms',
            );
        // @codingStandardsIgnoreEnd

        foreach ($Patterns as $Pattern)
        {
            if (preg_match($Pattern, $Export, $Matches))
            {
                $Modulus = $Matches[1];
                $Exponent = $Matches[2];
                break;
            }
        }

        # Clean newlines and whitespace out of the modulus
        $Modulus = preg_replace("/[^0-9a-f]/", "", $Modulus);

        # Return key material
        return array( "Modulus" => $Modulus, "Exponent" => $Exponent );
    }
}
