<?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 --------------------------------------------------

    # object constructor
    function SPTUser($UserInfo = NULL)
    {
        # call parent constructor
        $this->User($UserInfo);
    }

    /**
       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
     */
    static function GetCryptKey()
    {
        $DB = new Database();

        # Clear all keys more than two days old
        $DB->Query("DELETE FROM LoginKeys WHERE NOW() - CreationTime > 172800");
        $DB->Query("DELETE FROM UsedLoginTokens WHERE NOW()-KeyCTime > 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"] );
        }

        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
     */
    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 = "";

        $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',
            );

        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 );
    }

}
