<?php
###############################################################################
# SSL.php
#
# @author Anil Kumar <akumar@codepunch.com>
# @link   https://codepunch.com
#
############################################################################### 

namespace 	CodePunch\Pro;
use 		CodePunch\Base\Util as UTIL;
use			CodePunch\Base\Text as TEXT;

###############################################################################

class SSL  {
	
	private $authentication = null;
	
	###########################################################################
	
	private $ssl_table_xlate			= array(
											'ssl_valid_from' => 'valid_from',
											'ssl_valid_to' => 'valid_to',
											'ssl_issued_to' => 'issued_to',
											'ssl_issued_by' => 'issued_by',
											'subject_key_id' => 'subject_key_id',
											'subject_alt_name_text' => 'subject_alt_name_text',
											'subject_alt_name' => 'subject_alt_name',
											'signature_type' => 'signature_type',
											'serial' => 'serial',
											'added_on' => 'added_on',
											'sid' => 'sid'
											);
	
	###########################################################################
	
	public function __construct($auth=null) {
		$this->authentication = $auth;
	}
	
	###########################################################################
	
	private function openssl_to_timestamp ($in) 
	{
		$year  = substr($in, 0, 2); /* NOTE: Yes, this returns a two digit year */
		$month = substr($in, 2, 2);
		$day   = substr($in, 4, 2);
		$hour  = substr($in, 6, 2);
		$min   = substr($in, 8, 2);
		$sec   = substr($in, 10, 2);
		return gmmktime($hour, $min, $sec, $month, $day, $year);
	}
	
	###########################################################################
	
	public function addSSLCertificate($parsedssl, $cert, $domain="", $live_at="") {
		$db = $this->authentication->getDatabase();
		$ssldata = array();
		if(isset($parsedssl['serialNumber']) && isset($parsedssl['validFrom']) && isset($parsedssl['subject']['CN']) && isset($parsedssl['issuer']['CN'])) {
			$ssldata['valid_from'] = date("Y-m-d H:i:s", $this->openssl_to_timestamp($parsedssl['validFrom']));
			$ssldata['issued_to'] = $parsedssl['subject']['CN'];
			$ssldata['issued_by'] = $parsedssl['issuer']['CN'];
			$ssldata['serial'] = $parsedssl['serialNumber'];
			if(strlen($ssldata['serial']) > 2 && stripos($ssldata['serial'], "0x") === false && function_exists('bcmod')) {
				$dec = $ssldata['serial'];
				$hex = array();
				while ($dec) {
					$modulus = bcmod($dec, '16');
					array_unshift($hex, dechex($modulus));
					$dec = bcdiv(bcsub($dec, $modulus), 16);
				}
				$ssldata['serial'] = '0x' . strtoupper(implode('', $hex));
			}
			
			$params = array($ssldata['valid_from'], $ssldata['serial'], $ssldata['issued_by'], $ssldata['issued_to']);
			$hasrow = $db->hasRow($db->getSSLCertificateTableName(), array('valid_from', 'serial', 'issued_by', 'issued_to'), $params);
			if($hasrow) {
				// Delete and re-add if the data is more than a day old.
				$params[] = date("Y-m-d H:i:s", time() - 24*3600);
				$count = $db->deleteFromTable($db->getSSLCertificateTableName(), "valid_from=? AND serial=? AND issued_by=? AND issued_to=? AND added_on < ?", $params);
				$hasrow = (($count !== false && $count == 1) ? false : true);
			}
			if(!$hasrow) {
				if(isset($parsedssl['validTo']))
					$ssldata['valid_to'] = date("Y-m-d H:i:s", $this->openssl_to_timestamp($parsedssl['validTo']));
				if(isset($parsedssl['issuer']['O']))
					$ssldata['issuer_organization'] = $parsedssl['issuer']['O'];
				if(isset($parsedssl['issuer']['C']))
					$ssldata['issuer_country'] = $parsedssl['issuer']['C'];
				if(isset($parsedssl['extensions']['subjectKeyIdentifier']))
					$ssldata['subject_key_id'] = $parsedssl['extensions']['subjectKeyIdentifier'];
				if(isset($parsedssl['extensions']['subjectAltName'])) {
					$ssldata['subject_alt_name_text'] = $parsedssl['extensions']['subjectAltName'];
					$ssldata['subject_alt_name'] = substr($parsedssl['extensions']['subjectAltName'], 0, 2047);
				}
				$signtypeln = "";
				$signtypesn = "";
				if(isset($parsedssl['signatureTypeLN']))
					$signtypeln = $parsedssl['signatureTypeLN'];
				if(isset($parsedssl['signatureTypeSN']))
					$signtypesn = $parsedssl['signatureTypeSN'];
				$ssldata['signature_type'] = "$signtypeln [$signtypesn]";
				$ssldata['added_on'] = date("Y-m-d H:i:s");
				if($domain != "") {
					$ssldata['sid'] = $db->getDomainID($domain);
					$ssldata['base_domain'] = $domain;
					$ssldata['auto_added'] = 1;
				}
				else
					$ssldata['auto_added'] = 0;
				$ssldata['live_at'] = $live_at;
				$ssldata['thumbprint'] = openssl_x509_fingerprint($cert);
				$astat = $db->insertIntoTable($db->getSSLCertificateTableName(), $ssldata);
				UTIL::debug_cli_print($ssldata);
				return ($astat !== false ? true : false);
			}
		}
		return false;
	}
	
	# convert to SSL Cerfificate table columns
	private function getSSLTableData($sdssldata) {
		$db = $this->authentication->getDatabase();
		$sslrow = array();
		foreach($sdssldata as $key=>$val) {
			foreach($this->ssl_table_xlate as $xk=>$xv) {
				if($key == $xk) {
					$sslrow[$xv] = $val;
				}
			}
		}
		if(isset($sslrow['sid'])) {
			$sslrow['base_domain'] = $db->getDomainName($sslrow['sid']);
			$subdomain = $sdssldata['subdomain'] . "." . $sslrow['base_domain'];
			$subdomain = str_replace("@.", "", $subdomain);
			$sslrow['live_at'] = $subdomain;
		}
		return $sslrow;
	}
	
	# Import SSL certificate data from subdomain table to sslcerts table
	public function importSSLCertsFromSubdomains($deleteold=false) {
		$db = $this->authentication->getDatabase();
		if($deleteold) {
			$db->deleteFromTable($db->getSSLCertificateTableName(), "auto_added=?", array(1));
		}
		
		$added = 0;
		$rows = $db->getFromTable("*", $db->getSubdomainTableName(), "serial is not null and auto_added=2 and ssl_valid_from is not null", array(), "serial", "asc");
		if($rows !== false && count($rows)) {
			$index = 0;
			foreach($rows as $row) {
				$row = $db->fetchRow($rows, $index);
				$index++;
				$sslrow = $this->getSSLTableData($row);
				UTIL::debug_cli_print($sslrow);
				if($db->hasRow($db->getSSLCertificateTableName(), array('valid_from', 'serial', 'issued_by', 'issued_to'), array($sslrow['valid_from'], $sslrow['serial'], $sslrow['issued_by'], $sslrow['issued_to'])) === false) {
					$sslrow['auto_added'] = 1;
					$astat = $db->insertIntoTable($db->getSSLCertificateTableName(), $sslrow);
					if($astat !== false)
						$added++;
				}
			}
			UTIL::debug_cli_print($added);
		}
		return $added;
	}
}
