<?php
/*
  This code is part of FusionDirectory (http://www.fusiondirectory.org/)

  Copyright (C) 2003  Cajus Pollmeier
  Copyright (C) 2011-2020  FusionDirectory

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/

/* Require TOTP and dependencies */
require_once('variables_webauthn.inc');

class TOTPAddDialog extends GenericDialog
{
  protected $otp;
  protected $otpcode;

  function __construct ($simplePlugin, $attribute)
  {
    global $config;

    $this->attribute = $attribute;

    /* Create a TOTP object */
    $this->otp = OTPHP\TOTP::create(
      NULL,
      $config->get_cfg_value('TotpPeriod', 30),
      $config->get_cfg_value('TotpDigest', 'sha1'),
      $config->get_cfg_value('TotpDigits', 6)
    );
    $this->otp->setLabel($this->attribute->getUserUid());
    $this->otp->setIssuer(URL::getHostName());
    $this->otp->setParameter('image', URL::buildAbsoluteUrl('/geticon.php?context=applications&icon=fusiondirectory&size=48'));
    $this->dialog = TRUE;
  }

  public function readPost ()
  {
    if (isset($_POST[$this->post_cancel])) {
      $this->handleCancel();
    } else {
      $this->otpcode = ($_POST['otpcode'] ?? '');
      if (isset($_POST[$this->post_finish]) || isset($_GET[$this->post_finish])) {
        $this->handleFinish();
      }
    }
  }

  public function update (): bool
  {
    return isset($this->dialog);
  }

  public function render (): string
  {
    global $config;

    $provisioningUri = $this->otp->getProvisioningUri();

    /* Render */
    $smarty = get_smarty();

    $smarty->assign('usePrototype', 'true');

    $smarty->assign('section',        _('Add TOTP device'));
    $smarty->assign('sectionId',      'totp');
    $smarty->assign('sectionClasses', '');
    $attributes = [];
    $attributes['otpuri'] = [
      'htmlid'        => 'otpuri',
      'label'         => '{literal}'._('QR Code').'{/literal}',
      'description'   => _('Scan this QR code and enter an OTP code below'),
      'input'         => '<img src="qrcode.php?data='.urlencode($provisioningUri).'" alt="'.$provisioningUri.'"/>',
      'subattribute'  => FALSE,
      'required'      => FALSE,
      'readable'      => TRUE,
      'writable'      => FALSE,
    ];
    $attributes['otpcode'] = [
      'htmlid'        => 'otpcode',
      'label'         => '{literal}'._('Code').'{/literal}',
      'description'   => _('After scanning the QR code, enter here the digits generated by you OTP device or application'),
      'input'         => '<input type="text" name="otpcode" id="otpcode" required="required"/>',
      'subattribute'  => FALSE,
      'required'      => TRUE,
      'readable'      => TRUE,
      'writable'      => TRUE,
    ];
    $smarty->assign('attributes', $attributes);
    $sections = [
      'totp' => $smarty->fetch(get_template_path('simpleplugin_section.tpl'))
    ];
    $smarty->assign('sections', $sections);
    $smarty->assign('hiddenPostedInput', get_class($this).'_posted');

    return $smarty->fetch(get_template_path('simpleplugin.tpl'))."\n".$this->buttons();
  }

  protected function buttons (): string
  {
    return '<div style="width:100%; text-align:right; clear:both; float:none;">'.
           '  <input type="submit" name="'.$this->post_finish.'" value="'.msgPool::addButton().'"/>&nbsp;'.
           '  <input type="submit" formnovalidate="formnovalidate" name="'.$this->post_cancel.'" value="'.msgPool::cancelButton().'"/>'.
           '</div>';
  }

  protected function check (): array
  {
    /* Check that code was filled and correct */
    if (empty($this->otpcode)) {
      return [_('OTP code missing')];
    } elseif (!$this->otp->verify($this->otpcode)) {
      return [_('Wrong OTP code')];
    }

    return [];
  }

  protected function handleFinish ()
  {
    $msgs = $this->check();
    if (count($msgs)) {
      msg_dialog::displayChecks($msgs);
      return;
    }

    $this->attribute->addValue('', [date('Y-m-d'), $this->otp->getProvisioningUri()]);
    unset($this->dialog);
  }
}
