Miscellaneous additions (previously untracked)

This commit is contained in:
Miguel Nogueira
2019-01-25 14:17:48 +00:00
parent 437d81838a
commit a8f089e3b2
7 changed files with 52 additions and 4 deletions

View File

@@ -0,0 +1,30 @@
<?php
class Auth
{
public $AdminID;
private $ApiTools;
public function __construct($AdminID)
{
$this->ApiTools = new ApplicationAPI($AdminID);
$this->AdminID = $AdminID;
}
public function Auth($key)
{
if ($this->ApiTools->keysMatch($key))
{
return true;
}
else
{
throw new Exception("FATAL: Invalid API key");
}
}
}

View File

@@ -0,0 +1,86 @@
<?php // THIS CLASS ENFORCES GDPR COMPLIANCE. USING A WORKAROUND FOR THIS CONSTITUTES A VIOLATION OF THE SPACEJEWEL TERMS OF SERVICE.
// This mailer won't let you mail anyone unless they are registered as a customer to prevent GDPR violation.
// Additionally, it doesn't let you send anything else other than mandatory email (like service downtime notifications) unless
// they explicitly provided GDPR consent
class Emailer
{
private $Customer;
private $CustomerEmail;
private $CustomerID;
private $Envelope;
private $Mailer;
// Initialize mailer for this customer ID
public function __construct($CustomerEmail)
{
$this->Customer = new Customer();
// WARNIMG: Function might return wrong data, use var_dump to inspect
$CID = $this->Customer->translateEmailToID($CustomerEmail);
$this->CustomerId = $CID;
// We might want to use $CID in this method, so shortening isn't feasible here
if(!$this->Customer->customerExists($CustomerEmail))
{
// Customer doesn't exist, fail here
throw new Exception("Fatal error! Sending an email to an unregistered person is not allowed (GDPR Error Code: #1). A customer can be registered by purchasing a subscription");
}
$this->prepareMailerEnvelope();
}
private function prepareMailerEnvelope()
{
$config = new Config();
$cConfigArray = $config->getConfig();
$username = $cConfigArray['mailer']['username'];
$password = $cConfigArray['mailer']['password'];
$hostname = $cConfigArray['mailer']['hostname'];
$port = $cConfigArray['mailer']['port'];
$connStr = 'tls://' . $username . ":" . $password . "@" . $hostname . ":" . $port;
$this->Envelope = new ByJG\Mail\Envelope();
\ByJG\Mail\MailerFactory::registerMailer('smtp', \ByJG\Mail\Wrapper\PHPMailerWrapper::class);
$this->Mailer = \ByJG\Mail\MailerFactory::create($connStr);
$this->Mailer->setFrom("noreply@spacejewel-hosting.com", "Spacejewel Billing System");
$this->Mailer->addTo($this->CustomerEmail);
}
public function addSubject($subject)
{
$this->Mailer->setSubject($subject);
}
public function setBody($body)
{
$this->Mailer->setBody($body);
}
public function sendEnvelope()
{
$Mailer->send($this->Envelope);
}
}

View File

@@ -0,0 +1,230 @@
<?php
use \Slim\Http\Request as Request;
use \Slim\Http\Response as Response;
use Yadakhov\Json as Json;
// The hookmanager is the web-exposed class that allows you to manage a user within the billing system.
// This system takes care of CRUD operations on customers. It doesn't keep track of order but it does suspend
// you if you don't pay.
class Hookmanager
{
private $Customer;
private $Renderview;
private $APITools;
private $Mailer;
// Can be overloaded by child classes in order to add new features.W
protected $alertTypes =
[
"subscription_created",
"subscription_updated",
"subscription_cancelled",
"subscription_payment_succeeded",
"subscription_payment_failed",
"subscription_payment_refunded",
"payment_refunded"
];
private $AppBaseURL;
public function __construct()
{
$this->Customer = new Customer();
$this->Renderview = new EmailRenderer();
$this->APITools = new ApplicationAPI();
$this->JsonHelper = new Json();
// Create mailer when needed
}
private function keyValidate($keyFromURI)
{
// FIXME: Theoretically, this method does not work.
// TODO: Devise a new way to validate keys without user ID
if($this->APITools->keysMatch($keyFromURI))
{
return true;
}
else
{
return false;
}
}
/**
*
* This function detects the intent within the payload.
* After doing so, it returns the intent back to you so that you can perfom the correct redirect
*
*/
public function detectPayloadIntent(Request $request, Response $response, $args)
{
if ($this->keyValidate($keyFromURI))
{
$data = $this->getStructuredVariableList($Request);
foreach ($this->alertTypes as $types => $value)
{
if ($types == $data['alert_name'])
{
$sVal = $value;
}
}
// Uses the response and redirect objects and the intent from the current request to redirect it
$this->redirectAlert($request, $response, $sVal);
}
throw new LogicException("Illegal API key");
}
// The response and request method is passed by the redirecting method
private function redirectAlert(Request $Request, Response $response, $intent)
{
switch ($intent)
{
// This serves as a proxy to all other methods
case "subscription_created":
$this->EventSubscriptionCreated($Request, $response);
break;
case "subscription_updated":
$this->EventSubscriptionUpdated($Request, $response);
break;
case "subscription_cancelled":
$this->EventSubscriptionCancelled($Request, $response);
break;
case "subscription_payment_successful":
$this->EventSubscriptionPaymentSuccess($Request, $response);
break;
case "subscription_payment_failed":
$this->EventSubscriptionPaymentFailed($Request, $response);
break;
case "subscription_payment_refunded":
$this->EventSubscriptionPaymentRefunded($Request, $response);
break;
default:
$this->JsonHelper->set
([
"status" => "fail",
"message" => "Error: Invalid alert type (Or middleman attack in-progress)",
"code" => 500
]);
// Writing JsonHelper while it's not a string but an object will cause it to fire it's __toString method, which
// assembles the JSON defined in the array notation as written above in the form of an array.
// Calling Slim's withStatus method gives us the ability to tell the client something went wrong.
return $response->write($this->JsonHelper)->withStatus(500);
}
}
// Return POST variable list in a structured array, DRY
private function getStructuredVariableList(Request $request)
{
$PDATA = $request->getParsedBody();
$dArr = $PDATA;
return $dArr;
}
public function EventSubscriptionCreated(Request $request, Response $response, $args)
{
return $response->write($this->getStructuredVariableList($Request))->withStatus(200);
}
public function EventSubscriptionUpdated(Request $request, Response $response, $args)
{
// Update user information if necessary
}
public function EventSubscriptionCancelled(Request $request, Response $response, $args)
{
// Suspend user's domain name as stated on DB
// Delete after 30 days
}
public function EventSubscriptionPaymentSuccess(Request $request, Response $response, $args)
{
// Renew user's subscription within billing system
// Install hosting account if this is the user's first time and send out instructions email
}
// TODO: Lenient business logic
public function EventSubscriptionPaymentFailed(Request $request, Response $response, $args)
{
// Add payment strike to user account
// After three strikes, warn user that the system has waived further attempts. Suspend their account
// Give user an ultimatum: Pay or remain suspended
// If user fails to pay during the next 7 days, permanently suspend their account (Reject further payments. Remove user from paddle first)
// If payment is successful afterwards, remove all payment strikes (Success logic should execute automatically)
}
public function EventSubscriptionPaymentRefunded(Request $request, Response $response, $args)
{
// Ban customer from billing system
// Delete all customer data
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
*
* This class is part of the Application core logic, since it handles customer packages.
*
*/
class Package extends Application
{
const PACKAGE_STARTER = "P_STARTER";
const PACKAGE_SMALLCOMPANY = "P_SCOMPANY";
const PACKAGE_PROFESSIONAL = "P_PROFESSIONAL";
const PACKAGE_ENTERPRISE = "P_ENTERPRISE";
const PACKAGE_UNLIMITED = "P_UNLIMITED";
private $allowedPackages =
[
"P_STARTER",
"P_SMALLCOMPANY",
"P_PROFESSIONAL",
"P_ENTERPRISE",
"P_UNLIMITED"
];
private $AdminID;
public function __construct()
{
$this->AdminID = $AdminID;
}
public function getDefaultOptionsArray()
{
return
[
"desc" => "Created by Spacejewel Billing System",
"dir",
"unix",
"webmin",
"web",
"dns",
"mail",
"ssl",
"spam",
"virus",
"limits-from-plan"
];
}
}

View File

@@ -0,0 +1,45 @@
<?php
class EmailRenderer
{
private $templateDir;
public $twig;
public $tmeplateList = [
"accountBillingInformation",
"accountCancellationNotice",
"accountInformationUpdated",
"accountInstallation",
"accountRefunded",
"accounSubscriptionPaymentFailed"
];
public function __construct()
{
$config = new Config();
$cConfigArray = $config->getConfig();
$loader = new Twig_Loader_Filesystem($cConfigArray['templates']['templatesDirectory']);
$this->twig = new Twig_Environment($loader);
}
public function renderTemplate($Tmpl, Array $Data)
{
// $Data is an associative array of data
if(!in_array($this->templateList, $Tmpl))
{
throw new Exception("WARNING: Selected template not available");
}
else
{
return $this->twig->render($Tmpl, $Data);
}
}
}

View File

@@ -0,0 +1,114 @@
<?php
use \HnhDigital\Virtualmin as Virtualmin;
// This class serves as a mini wrapper to HnhDigital's wrapper class.
// It takes the methods it needs and proxies them for applicational use.
class VirtualminHandler
{
private $virtualmin;
public function __construct()
{
$Config = new Config();
$cConfigArray = $Config->getConfig();
$url = $cConfigArray['virtualmin']['vmin-url'];
$username = $cConfigArray['virtualmin']['username'];
$password = $cConfigArray['virtualmin']['password'];
$this->virtualmin = new Virtualmin\VirtualServersClient($url, $username, $password);
}
// Creates a domain with the specified password. The username will be the domain with the .tld removed.
// The features array will be populated when the method is exposed with the correct package name provided.
public function CreateVirtualServer($DomainName, $Password, Array $Features = [])
{
return $this->virtualmin->create($DomainName, $Password, $Features);
}
public function DeleteVirtualServer($DomainName)
{
return $this->virtualmin->delete($DomainName);
}
// NOTICE! This deletes all domain names linked to a user account. This action is IRREVERSIBLE!
public function DeleteAllFromUser($User)
{
return $this->virtualmin->deleteByUser($User);
}
public function SuspendVirtualServer($DomainName, $SuspensionReason)
{
// TODO: Flag account as inactive within system's database (At Hookmanager class)
return $this->virtualmin->suspend($DomainName, $SuspensionReason);
}
public function DisableFeature($DomainName, $FeatureName)
{
return $this->virtualmin->disableFeatureByDomain($DomainName, $FeatureName);
}
// Deattaches all features from all domains by this user
public function DisableFeaturesByUser($Username, $Features)
{
return $this->virtualmin->disableFeatureByUser($Username, $Feature);
}
public function DisableFeatureFromAllDomains($FeatureName)
{
return $this->virtualmin->disableFeatureAllDomains($Feature);
}
public function EnableFeatureByDomain($Domain, $Feature)
{
return $this->virtualmin->enableFeatureByDomain($Domain, $Feature);
}
public function enableFeatureByUser($User, $Feature)
{
return $this->virtualmin->enableFeatureByUser($User, $Feature);
}
public function enableFeatureAllDomains($Feature)
{
return $this->virtualmin->enableFeatureAllDomains($Feature);
}
// SPECIAL: GDPR READINESS
// This
public function modifyDomain($Domain, Array $ModifiableOptions)
{
$optionsArr =
[
"domain" => $Domain
];
return $this->virtualmin->modifyDomain(array_merge($optionsArr, $ModifiableOptions));
}
}