<?php
/**
 * DokuWiki Plugin gtime (Action Component)
 *
 * @license Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0
 * @author  Michael Kirchner <michael@hirnreck.de>
 */

/*
 * Copyright (C) Michael Kirchner <michael@hirnreck.de>
 *
 * This file is part of the GuardTime dokuwiki plugin.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 
 


// must be run within Dokuwiki
if (!defined('DOKU_INC')) die();

if (!defined('DOKU_LF')) define('DOKU_LF', "\n");
if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');

// error_reporting(E_ALL);
// ini_set('display_errors', 'On');

require_once DOKU_PLUGIN.'action.php';
require_once(DOKU_INC.'inc/pluginutils.php'); 


class action_plugin_gtime_timestamp extends DokuWiki_Action_Plugin {

    // todo:
    // Button to download zip with file and timestamp data
    // include setup variables into dokuwiki setup

    public function register(Doku_Event_Handler &$controller) {
        $Timestamper_URL=$this->getConf('Timestamper_URL');
        //The URL of the service for creating timestamps.

        $Extender_URL=$this->getConf('Extender_URL');
        //The URL of the service for connecting timestamps to Integrity Codes.

        $Publications_URL=$this->getConf('Publications_URL');
        //The URL where the GuardTime publications file can be downloaded.

        $Publications_TTL=$this->getConf('Publications_TTL');
        //Time of life for Publicationsfile in minutes

        $controller->register_hook('IO_WIKIPAGE_WRITE', 'AFTER', $this, 'handle_io_wikipage_write');
        $controller->register_hook('TPL_ACT_RENDER', 'AFTER', $this, 'handle_tpl_act_render');
    }


    /**
     * Logs exception and stack trace to error log.
     *
     * @param  $exception the exception to log
     * @return void
     */
    function gt_log_exception($exception) {
    
        error_log($exception->getMessage());
        error_log($exception->getTraceAsString());
    }



    /**
     * Gets publications file.
     *
     * This method uses gt_publications_file to cache the file for
     * publications_ttl minutes in tmp.
     *
     * @return GTPublicationsFile cached or freshly downloaded publications file
     */

    
    function gt_publications_file() {
    
        $Publications_URL=$this->getConf('Publications_URL');
        //The URL where the GuardTime publications file can be downloaded.

    
        if (empty($Publications_URL)) {
            return null;
        }
    
        $Publications_TTL=$this->getConf('Publications_TTL');
        //Time of life for Publicationsfile in minutes
    
        if (!is_integer($Publications_TTL)) {
            $ttl = 60;
        }
    
        $Publications_TTL = $Publications_TTL * 60 ;


        $filename = DOKU_INC.'/data/tmp/publications.bin';

        if (file_exists($filename)) {
            $filetime = filemtime($filename);
        }
    
        if (empty($filetime) || ($filetime + $Publications_TTL) < time()) {
    
    
            try {
    
                $newFile = GTHttpClient::getPublicationsFile($Publications_URL);
                $result = $newFile->verify();
    
                if ($result->isValid()) {
                    $newFile->save($filename);
                    return $newFile;
                } else {
                    return null;
    
                }
            } catch (GTException $e) {
                gt_log_exception($e);
            }
    
        }
    
        try {
            return GTPublicationsFile::load($filename);
    
        } catch (GTException $e) {
            gt_log_exception($e);
    
        }
    }
        
     
    /**
     * Extends GuardTime timestamp.
     *
     * @param  $timestamp
     * @param  $INFO
     * @return void
     */
    function gt_extend($timestamp,$INFO) {

        $Publications_URL=$this->getConf('Publications_URL');
        //The URL where the GuardTime publications file can be downloaded.
    
        if ($timestamp->isExtended()) {
            return;
        }
    
        $Extender_URL=$this->getConf('Extender_URL');
    
        if (empty($Extender_URL)) {
            return;
        }
    
        $publicationsFile = $this->gt_publications_file();

    
        if (empty($publicationsFile)) {
            return;
        }
    
        if (!$timestamp->isExtendable($publicationsFile)) {
            return;
            // What does that mean? only PKI signed?
        }
    
        try {
    
            GTHttpClient::extend($timestamp, $Extender_URL);
    
        } catch (GTException $e) {
            $this->gt_log_exception($e);
        }
    
        if ($timestamp->isExtended()) {
            $timestamp->save($INFO['filepath'].'.gtts');
        }
    }
     
        

    /**
     * Main Handle for Timestamping.
     *
     * @param  $event
     * @param  $param
     * @return void
     */
    public function handle_io_wikipage_write(Doku_Event &$event, $param) {

        // This routine is called when a file is written in pages or attic.
        // Whenever we do this, a timestamp is created and stored with the file with extension gtts.
        // (The exception is when the file is deleted with empty content, then no new timestamp is
        // needed and the old timestampfile is deleted.)
        // While this is also done on the aktual pages, it is also done on the attic. This is
        // actually more important, as the attic is always kept. Be aware that when using compression
        // the timestamp will be on the compressed files!
        

        require_once(DOKU_INC.'lib/plugins/gtime/gtlib/guardtime.php');

        $Timestamper_URL=$this->getConf('Timestamper_URL');
        //The URL of the service for creating timestamps.


        $data = $event->data; 

        // For debugging:
        // $finfo = "";
        // if ($data[0][1]=="") $finfo = " Empty";
        // if (!file_exists($data[0][0])) { $finfo .= " New"; } else { $finfo .= " Exists" ;};
        // error_log("Filename: ".$data[0][0].$finfo." NS: ".$data[1]." ID: ".$data[2]." Rev: ".$data[3]);

        if ($data[0][1]=="") {
            // No content means the file is deleted
            // so the Timestamp should be deleted too, otherwise we clutter the dir
            unlink ($data[0][0].'.gtts');
        }
        else {

            // hash the data file (not content!) using the default algorithm (currently SHA-256)
            $dataHash = new GTDataHash(GTHashAlgorithm::getByName('DEFAULT'));
            $dataHash->updateFile($data[0][0]);
            $dataHash->close();

             
            // request a timestamp for the hash value
            try {
                $timestamp = GTHttpClient::create($dataHash, $Timestamper_URL);
            } catch (GTException $e) {
               $this->gt_log_exception($e);
            }

            
            // save the timestamp for archiving it along with the data file
            $timestamp->save($data[0][0].'.gtts');
        }


    }


    /**
     * Handle for Output of Timestamping information at the page bottom.
     *
     * @param  $event
     * @param  $param
     * @return void
     */

    public function handle_tpl_act_render(Doku_Event &$event, $param) {
        global $ID;
        global $REV;
        global $INFO;
        global $conf;
        global $ACT;
        global $mylang;

        $this->setupLocale();
        $mylang=$this->lang;

        require_once(DOKU_INC.'lib/plugins/gtime/gtlib/guardtime.php');

        $Publications_URL=$this->getConf('Publications_URL');
        //The URL where the GuardTime publications file can be downloaded.

        
        //only when show action, page exists and its ID matches with settings
        if ($ACT == 'show' && $INFO['exists'] ){

            if (file_exists($INFO['filepath'].".gtts") ) {
                // load the timestamp
                // error_log("Info-Filepath: ".$INFO['filepath']);
                $timestamp = GTTimestamp::load($INFO['filepath'].".gtts");
    
                // Extend timestamp
                if (!$timestamp->isExtended()) {
                    $this->gt_extend($timestamp,$INFO);
                } 
                           
                // hash the data file using the algorithm from the timestamp
                $dataHash = new GTDataHash($timestamp->getHashAlgorithm());
                $dataHash->updateFile($INFO['filepath']);
                $dataHash->close();
    
                // load the publications file
                // we assume it's trusted local copy and skip verification here
                $publicationsFile = $this->gt_publications_file();
    
                try {
                    // verify against the publications file
                    $result = GTHttpClient::verify($timestamp, $dataHash, null, $publicationsFile);
    
                } catch (GTException $e) {
                    $this->gt_log_exception($e);
                }
    
                if ($result->isValid()) {
                    $invalid_warning ="";
                } else {
                    $invalid_warning ='<span class="guardtime_timestamp_invalid">'.$mylang['Validation_failed'].'</span>';
                }
    
                //This, by some reason does not work with caching
                $link_to_download = exportlink($ID,"gtime",$REV==true ? "rev=$REV,purge=true": "purge=true");



                $valid_summary=<<<EOT
    <div class="guardtime_timestamp_summary">


        <a href="http://www.guardtime.com" title="Timestamped by GuardTime"><img
                src="lib/plugins/gtime/assets/guardtime.png" alt="Timestamped by GuardTime"/></a>

        <span>
        $invalid_warning
            {$mylang['pagesign']} {$timestamp->getProperty(GTTimestamp::REGISTERED_TIME)}
            <a href="javascript:toggel_GT_Details();" class="guardtime_timestamp_buttons">{$mylang['Details_Button']}</a>

            <a href=$link_to_download class="guardtime_timestamp_buttons">{$mylang['Download_Button']}</a>
        </span>

        <div class="clear"></div>

    </div> 

EOT;


         $valid_details=<<<EOT
    <div class="guardtime_timestamp_details" id="guardtime_timestamp_details" style="display: none;">
        <table cellpadding="0" cellspacing="0" border="0" class="guardtime_details">
            <tbody>

            <tr>
                <td>{$mylang['Registration_Time']}</td>
                <td>{$timestamp->getProperty(GTTimestamp::REGISTERED_TIME)}</td>
            </tr>

            <tr>
                <td>{$mylang['Integrity_Code']}</td>
                <td>{$timestamp->getProperty(GTTimestamp::PUBLICATION)}</td>
            </tr>

            <tr>
                <td>{$mylang['History_Checkpoint']}</td>
                <td>{$timestamp->getProperty(GTTimestamp::PUBLICATION_TIME)}</td>
            </tr>

            <tr>
                <td>{$mylang['Issuer_Name']}</td>
                <td>{$timestamp->getProperty(GTTimestamp::ISSUER_NAME)}</td>
            </tr>

            <tr>
                <td>{$mylang['Policy']}</td>
                <td>{$timestamp->getProperty(GTTimestamp::POLICY_ID)}</td>
            </tr>

            <tr>
                <td>{$mylang['Hash_Algorithm']}</td>
                <td>{$timestamp->getHashAlgorithm()->getName()}</td>
            </tr>

            <tr>
                <td>{$mylang['Message_Hash']}</td>
                <td>{$timestamp->getProperty(GTTimestamp::HASHED_MESSAGE)}</td>
            </tr>

            <tr>
                <td>{$mylang['Error_Code']}</td>
                <td>{$result->getGtResult()->getErrorCode()}</td>
            </tr>

            <tr>
                <td>{$mylang['Status_Code']}</td>
                <td>{$result->getGtResult()->getErrorCode()}</td>
            </tr>

            </tbody>
        </table>
    </div> 

EOT;

            } else {

                $invalid_warning ='<span class="guardtime_timestamp_invalid">'.$mylang['Timestamp_missing'].'</span>';
                $valid_summary=<<<EOT
    <div class="guardtime_timestamp_summary">
        <a href="http://www.guardtime.com" title="Timestamped by GuardTime"><img
                src="lib/plugins/gtime/assets/guardtime.png" alt="Timestamped by GuardTime"/></a>
        <span>
        $invalid_warning
        </span>
        <div class="clear"></div>
    </div> 

EOT;
         $valid_details=<<<EOT
EOT;

            }



            $valid_output=<<<EOT
<div class="guardtime_timestamp"> 
    $valid_summary
    $valid_details
</div>

EOT;

            print $valid_output;


        }

    } 

}

// vim:ts=4:sw=4:et:
