Created File* backends
This commit is contained in:
parent
57a2da32cb
commit
498e00b7d2
6
composer.lock
generated
6
composer.lock
generated
@ -22,7 +22,7 @@
|
||||
"require-dev": {
|
||||
"symfony/finder": "2.1.*"
|
||||
},
|
||||
"time": "2012-09-01 01:02:36",
|
||||
"time": "2012-09-01 07:02:36",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -69,7 +69,7 @@
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"time": "2012-09-18 12:09:52",
|
||||
"time": "2012-09-18 16:09:52",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -128,7 +128,7 @@
|
||||
"symfony/yaml": "2.1.*",
|
||||
"doctrine/common": ">=2.2,<2.4-dev"
|
||||
},
|
||||
"time": "2012-09-10 08:53:42",
|
||||
"time": "2012-09-10 10:53:42",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
22
json_sms.php
22
json_sms.php
@ -10,9 +10,9 @@ use Symfony\Component\Routing\Matcher\UrlMatcher;
|
||||
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
|
||||
|
||||
use SmsGateway\Sender\GnokiiSender;
|
||||
use SmsGateway\Logger\DatabaseLogger;
|
||||
use SmsGateway\Backend\DatabaseBackend;
|
||||
use SmsGateway\Sender\FileSender;
|
||||
use SmsGateway\Logger\FileLogger;
|
||||
use SmsGateway\Auth\FileAuth;
|
||||
use SmsGateway\RpcServer;
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
@ -56,7 +56,7 @@ if (!array_key_exists('method', $jsonData) || !array_key_exists('params', $jsonD
|
||||
$wantResponse = (!empty($jsonData['id']));
|
||||
|
||||
try {
|
||||
$sender = new GnokiiSender();
|
||||
$sender = new FileSender('/var/www/html/smsgateway/app/cache/sms_spool');
|
||||
} catch (Exception $e) {
|
||||
$response = new Response('Internal Server Error: Sender cannot be instantiated.', 500);
|
||||
$response->send();
|
||||
@ -64,22 +64,26 @@ try {
|
||||
}
|
||||
|
||||
try {
|
||||
$logger = new DatabaseLogger('pgsql:host=127.0.0.1;dbname=smsgateway', 'smsgateway', 'Imuiwai8');
|
||||
} catch (PDOException $e) {
|
||||
$logger = new FileLogger('/var/www/html/smsgateway/app/logs/sms-message.log', '/var/www/html/smsgateway/app/logs/sms-audit.log');
|
||||
} catch (LogicException $e) {
|
||||
$response = new Response('Internal Server Error: Logger cannot be instantiated.', 500);
|
||||
$response->send();
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$backend = new DatabaseBackend();
|
||||
$auth = new FileAuth('/var/www/html/smsgateway/senders', '/var/www/html/smsgateway/app/cache/tokens');
|
||||
} catch (Exception $e) {
|
||||
$response = new Response('Internal Server Error: Backend cannot be instantiated.', 500);
|
||||
$response = new Response('Internal Server Error: Authenticator cannot be instantiated.', 500);
|
||||
$response->send();
|
||||
exit;
|
||||
}
|
||||
|
||||
$handler = new RpcServer($backend, $logger, $sender);
|
||||
$auth->setLogger($logger);
|
||||
$sender->setLogger($logger);
|
||||
|
||||
$handler = new RpcServer($auth, $logger, $sender);
|
||||
|
||||
try {
|
||||
$result = $handler->handle($request, $jsonData);
|
||||
} catch (Exception $e) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
<?php
|
||||
namespace SmsGateway\Backend;
|
||||
namespace SmsGateway\Auth;
|
||||
|
||||
use SmsGateway\AuthInterface;
|
||||
use SmsGateway\LoggerInterface;
|
||||
|
||||
class DatabaseAuth implements AuthInterface
|
||||
{
|
||||
|
142
src/SmsGateway/Auth/FileAuth.php
Normal file
142
src/SmsGateway/Auth/FileAuth.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
namespace SmsGateway\Auth;
|
||||
|
||||
use SmsGateway\AuthInterface;
|
||||
use SmsGateway\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Description of FileAuth
|
||||
*
|
||||
* @author Gergely Polonkai
|
||||
*/
|
||||
class FileAuth implements AuthInterface
|
||||
{
|
||||
private $logger;
|
||||
|
||||
private $sendersFile;
|
||||
|
||||
private $tokenFile;
|
||||
|
||||
public function __construct($sendersFile, $tokenFile) {
|
||||
if ($sendersFile == null) {
|
||||
throw new \InvalidArgumentException('A senders file path must be passed to the authenticator!');
|
||||
}
|
||||
|
||||
if (!is_readable($sendersFile)) {
|
||||
throw new \RuntimeException('senders file not readable!');
|
||||
}
|
||||
|
||||
if ($tokenFile == null) {
|
||||
throw new \InvalidArgumentException('A token file path must be passed to the authenticator!');
|
||||
}
|
||||
|
||||
if (
|
||||
(
|
||||
file_exists($tokenFile)
|
||||
&& !is_writable($tokenFile)
|
||||
)
|
||||
|| (
|
||||
!file_exists($tokenFile)
|
||||
&& !is_writable(dirname($tokenFile))
|
||||
)
|
||||
) {
|
||||
throw new \RuntimeException('Token file is not writable!');
|
||||
}
|
||||
|
||||
$this->sendersFile = $sendersFile;
|
||||
$this->tokenFile = $tokenFile;
|
||||
}
|
||||
|
||||
public function authenticate($username, $password, $ip, $sessionId)
|
||||
{
|
||||
$this->logger->auditLog(LoggerInterface::LOG_AUDIT_LOGIN, $username, "trying to authenticate");
|
||||
$lines = file($this->sendersFile);
|
||||
foreach ($lines as $line) {
|
||||
list($user, $cPassword) = explode(':', trim($line), 2);
|
||||
if ($user == $username) {
|
||||
if (crypt($password, $cPassword) == $cPassword) {
|
||||
$this->logger->auditLog(LoggerInterface::LOG_AUDIT_LOGIN, $username, "authenticated successfully");
|
||||
|
||||
return $this->getToken($username, $ip, $sessionId);
|
||||
} else {
|
||||
$this->logger->auditLog(LoggerInterface::LOG_AUDIT_LOGIN, $username, "authentication failed: bad password");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getTokenUsername($token, $ip, $sessionId)
|
||||
{
|
||||
$lines = file($this->tokenFile);
|
||||
foreach ($lines as $line) {
|
||||
list($tokenUser, $tokenIp, $tokenSession, $tokenToken) = explode(':', trim($line), 4);
|
||||
if (($tokenToken == $token) && ($tokenIp == $ip) && ($tokenSession == $sessionId)) {
|
||||
return $tokenUser;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function isTokenValid($token, $ip, $sessionId)
|
||||
{
|
||||
$this->logger->auditLog(LoggerInterface::LOG_AUDIT_LOGIN, null, 'Checking token validity');
|
||||
|
||||
$lines = file($this->tokenFile);
|
||||
foreach ($lines as $line) {
|
||||
list($tokenUser, $tokenIp, $tokenSession, $tokenToken) = explode(':', trim($line), 4);
|
||||
if (($tokenToken == $token) && ($tokenIp == $ip) && ($tokenSession == $sessionId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getToken($username, $ip, $sessionId) {
|
||||
$this->logger->auditLog(LoggerInterface::LOG_AUDIT_LOGIN, $username, "Getting token");
|
||||
|
||||
$lines = file($this->tokenFile);
|
||||
foreach ($lines as $line) {
|
||||
list($tokenUser, $tokenIp, $tokenSession, $tokenToken) = explode(':', trim($line), 4);
|
||||
if (($tokenUser == $username) && ($tokenIp == $ip) && ($tokenSession == $sessionId)) {
|
||||
return $tokenToken;
|
||||
}
|
||||
}
|
||||
|
||||
$token = str_replace(':', '', uniqid('', true));
|
||||
$fd = fopen($this->tokenFile, 'a');
|
||||
fwrite($fd, sprintf("%s:%s:%s:%s\n", $username, $ip, $sessionId, $token));
|
||||
fclose($fd);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
public function removeToken($token, $ip, $sessionId) {
|
||||
$username = $this->getTokenUsername($token, $ip, $sessionId);
|
||||
$this->logger->auditLog(LoggerInterface::LOG_AUDIT_LOGIN, $username, "Removing token");
|
||||
|
||||
$lines = file($this->tokenFile);
|
||||
$fd = fopen($this->tokenFile, 'w');
|
||||
foreach ($lines as $line) {
|
||||
list($tokenUser, $tokenIp, $tokenSession, $tokenToken) = explode(':', trim($line), 4);
|
||||
if (($tokenToken != $token) || ($tokenIp != $ip) || ($tokenSession != $sessionId)) {
|
||||
fwrite($fd, sprintf("%s:%s:%s:%s\n", $tokenUser, $tokenIp, $tokenSession, $tokenToken));
|
||||
}
|
||||
}
|
||||
fclose($fd);
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getLogger() {
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
public function setLogger(LoggerInterface $logger) {
|
||||
$this->logger = $logger;
|
||||
}
|
||||
}
|
@ -9,9 +9,13 @@ interface AuthInterface
|
||||
|
||||
public function getLogger();
|
||||
|
||||
public function authenticate($username, $password, $ip, $sessionId);
|
||||
|
||||
public function getToken($username, $ip, $sessionId);
|
||||
|
||||
public function isTokenValid($token, $ip, $sessionId);
|
||||
|
||||
public function removeToken($token, $ip, $sessionId);
|
||||
|
||||
public function getTokenUsername($token, $ip, $sessionId);
|
||||
}
|
||||
|
130
src/SmsGateway/Logger/FileLogger.php
Normal file
130
src/SmsGateway/Logger/FileLogger.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
namespace SmsGateway\Logger;
|
||||
|
||||
use SmsGateway\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Description of FileLogger
|
||||
*
|
||||
* @author Gergely Polonkai
|
||||
*/
|
||||
class FileLogger implements LoggerInterface
|
||||
{
|
||||
const PASSWORD_MASK = '[password]';
|
||||
|
||||
/**
|
||||
* The message log file
|
||||
*
|
||||
* @var resource $messageLogHandle
|
||||
*/
|
||||
private $messageLogHandle;
|
||||
|
||||
/**
|
||||
* The audit log file
|
||||
*
|
||||
* @var resource $auditLogHandle
|
||||
*/
|
||||
private $auditLogHandle;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $messageLogFile Name of the message log file
|
||||
* @param string $auditLogFile Name of the audit log file
|
||||
* @throws \LogicException Upon file opening error
|
||||
*/
|
||||
public function __construct($messageLogFile, $auditLogFile)
|
||||
{
|
||||
if ($messageLogFile == null) {
|
||||
throw new \LogicException('Message log file can not be null!');
|
||||
}
|
||||
|
||||
if ($auditLogFile == null) {
|
||||
throw new \LogicException('Audit log file can not be null!');
|
||||
}
|
||||
|
||||
if (
|
||||
(
|
||||
file_exists($messageLogFile)
|
||||
&& !is_writable($messageLogFile)
|
||||
)
|
||||
|| (
|
||||
!file_exists($messageLogFile)
|
||||
&& !is_writable(dirname($messageLogFile))
|
||||
)
|
||||
) {
|
||||
throw new \LogicException('Message log file is not writable!');
|
||||
}
|
||||
|
||||
if (
|
||||
(
|
||||
file_exists($auditLogFile)
|
||||
&& !is_writable($auditLogFile)
|
||||
)
|
||||
|| (
|
||||
!file_exists($auditLogFile)
|
||||
&& !is_writable(dirname($auditLogFile))
|
||||
)
|
||||
) {
|
||||
throw new \LogicException('Audit log file is not writable!');
|
||||
}
|
||||
|
||||
if (($this->messageLogHandle = fopen($messageLogFile, 'a')) === false) {
|
||||
throw new \LogicException('Message log file could not be opened!');
|
||||
}
|
||||
|
||||
if (($this->auditLogHandle = fopen($auditLogFile, 'a')) === false) {
|
||||
throw new \LogicException('Audit log file could not be opened!');
|
||||
}
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
fclose($this->messageLogHandle);
|
||||
fclose($this->auditLogHandle);
|
||||
}
|
||||
|
||||
private function orderPasswordLocations($a, $b)
|
||||
{
|
||||
if ($a[0] == $b[0]) {
|
||||
return 0;
|
||||
} elseif ($a[0] < $b[0]) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function messageLog($username, $recipient, $message, array $passwordLocations)
|
||||
{
|
||||
usort($passwordLocations, array($this, 'orderPasswordLocations'));
|
||||
|
||||
$encodedMessage = $message;
|
||||
$mod = 0;
|
||||
foreach ($passwordLocations as $loc) {
|
||||
list($pos, $length) = $loc;
|
||||
|
||||
$encodedMessage = substr_replace($encodedMessage, self::PASSWORD_MASK, $pos + $mod, $length);
|
||||
$mod += (strlen(self::PASSWORD_MASK) - $length);
|
||||
}
|
||||
|
||||
$logMessage = "From $username
|
||||
From: $username
|
||||
To: $recipient
|
||||
|
||||
$encodedMessage\n\n";
|
||||
|
||||
fwrite($this->messageLogHandle, $logMessage);
|
||||
fflush($this->messageLogHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function auditLog($type, $username, $message)
|
||||
{
|
||||
if ($username === null) {
|
||||
$logMessage = "$message\n";
|
||||
} else {
|
||||
$logMessage = "$username: $message\n";
|
||||
}
|
||||
fwrite($this->auditLogHandle, $logMessage);
|
||||
fflush($this->auditLogHandle);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ namespace SmsGateway;
|
||||
|
||||
interface LoggerInterface
|
||||
{
|
||||
const SMSSENDER_AUDIT_LOGIN = 1;
|
||||
const LOG_AUDIT_LOGIN = 1;
|
||||
|
||||
/**
|
||||
* Log an audit event
|
||||
@ -23,5 +23,5 @@ interface LoggerInterface
|
||||
* @param string $recipient The recipient of the message
|
||||
* @param string $message The message itself
|
||||
*/
|
||||
public function messageLog($username, $recipient, $message);
|
||||
public function messageLog($username, $recipient, $message, array $passwordLocations);
|
||||
}
|
@ -3,7 +3,7 @@ namespace SmsGateway;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
use SmsGateway\BackendInterface;
|
||||
use SmsGateway\AuthInterface;
|
||||
use SmsGateway\LoggerInterface;
|
||||
use SmsGateway\SenderInterface;
|
||||
|
||||
@ -12,9 +12,9 @@ class RpcServer
|
||||
/**
|
||||
* The user backend
|
||||
*
|
||||
* @var SmsGateway\BackendInterface $backend
|
||||
* @var SmsGateway\AuthInterface $backend
|
||||
*/
|
||||
private $backend;
|
||||
private $auth;
|
||||
|
||||
/**
|
||||
* The logger
|
||||
@ -30,23 +30,46 @@ class RpcServer
|
||||
*/
|
||||
private $sender;
|
||||
|
||||
public function __construct(BackendInterface $backend, LoggerInterface $logger, SenderInterface $sender)
|
||||
public function __construct(AuthInterface $auth, LoggerInterface $logger, SenderInterface $sender)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
$this->logger = $logger;
|
||||
$this->sender = $sender;
|
||||
}
|
||||
|
||||
protected function login(array $params)
|
||||
protected function login($username, $password)
|
||||
{
|
||||
return true;
|
||||
$token = $this->auth->authenticate($username, $password, $_SERVER['REMOTE_ADDR'], null);
|
||||
|
||||
if ($token === false) {
|
||||
throw new \Exception('Could not create token.');
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
protected function send(array $params)
|
||||
protected function send($token, $recipient, $message, array $passwordLocations)
|
||||
{
|
||||
return true;
|
||||
if (!$this->auth->isTokenValid($token, $_SERVER['REMOTE_ADDR'], null)) {
|
||||
throw new \Exception('Invalid token!');
|
||||
}
|
||||
|
||||
$this->sender->send($this->auth->getTokenUsername($token, $_SERVER['REMOTE_ADDR'], null), $recipient, $message, $passwordLocations);
|
||||
|
||||
// TODO: Send the message!
|
||||
|
||||
return 'success';
|
||||
}
|
||||
|
||||
protected function logout(array $params)
|
||||
protected function logout($token)
|
||||
{
|
||||
return true;
|
||||
if (!$this->auth->isTokenValid($token, $_SERVER['REMOTE_ADDR'], null)) {
|
||||
throw new \Exception('Invalid token!');
|
||||
}
|
||||
|
||||
$this->auth->removeToken($token, $_SERVER['REMOTE_ADDR'], null);
|
||||
|
||||
return 'success';
|
||||
}
|
||||
|
||||
public function handle(Request $request, array $jsonData)
|
||||
@ -54,14 +77,34 @@ class RpcServer
|
||||
$params = $jsonData['params'];
|
||||
switch ($jsonData['method']) {
|
||||
case 'login':
|
||||
if (count($params) != 2) {
|
||||
throw new \InvalidArgumentException('Bad parameter count!');
|
||||
}
|
||||
|
||||
return $this->login($params[0], $params[1]);
|
||||
|
||||
break;
|
||||
case 'send':
|
||||
if (count($params) != 4) {
|
||||
throw new \InvalidArgumentException('Bad parameter count!');
|
||||
}
|
||||
if (!is_array($params[3])) {
|
||||
throw new \InvalidArgumentException('Invalid 4th parameter!');
|
||||
}
|
||||
|
||||
return $this->send($params[0], $params[1], $params[2], $params[3]);
|
||||
|
||||
break;
|
||||
case 'logout':
|
||||
if (count($params) != 1) {
|
||||
throw new \InvalidArgumentException('Bad parameter count!');
|
||||
}
|
||||
|
||||
return $this->logout($params[0]);
|
||||
break;
|
||||
default:
|
||||
throw new \Exception('Invalid request');
|
||||
throw new \BadMethodCallException('Unknown method ' . $jsonData['method']);
|
||||
break;
|
||||
}
|
||||
return 'ajaj';
|
||||
}
|
||||
}
|
74
src/SmsGateway/Sender/FileSender.php
Normal file
74
src/SmsGateway/Sender/FileSender.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
namespace SmsGateway\Sender;
|
||||
|
||||
use SmsGateway\SenderInterface;
|
||||
use SmsGateway\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Description of FileSender
|
||||
*
|
||||
* @author Gergely Polonkai
|
||||
*/
|
||||
class FileSender implements SenderInterface
|
||||
{
|
||||
private $messageDir;
|
||||
|
||||
/**
|
||||
* @var SmsGateway\LoggerInterface $logger
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
public function __construct($messageDir)
|
||||
{
|
||||
if (file_exists($messageDir) && !is_dir($messageDir)) {
|
||||
throw new \InvalidArgumentException('Message directory specified is not a directory!');
|
||||
}
|
||||
|
||||
if (!file_exists($messageDir) && !is_writable(dirname($messageDir))) {
|
||||
throw new \RuntimeException('Message directory cannot be created');
|
||||
}
|
||||
|
||||
if (!file_exists($messageDir)) {
|
||||
mkdir($messageDir, 0777, true);
|
||||
}
|
||||
|
||||
if (!is_writable($messageDir)) {
|
||||
throw new \RuntimeException('Message directory is not writable!');
|
||||
}
|
||||
|
||||
$this->messageDir = $messageDir;
|
||||
}
|
||||
|
||||
public function setLogger(LoggerInterface $logger) {
|
||||
if ($logger === null) {
|
||||
throw new \InvalidArgumentException('A logger must be passed to the authenticator!');
|
||||
}
|
||||
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function getLogger() {
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
public function send($username, $recipient, $message, $passwordLocations)
|
||||
{
|
||||
$rcptDir = $this->messageDir . '/' . $recipient;
|
||||
|
||||
if (file_exists($rcptDir) && (!is_writable($rcptDir) || !is_dir($rcptDir))) {
|
||||
throw new \RuntimeException('Message directory is not writable!');
|
||||
}
|
||||
if (!file_exists($rcptDir)) {
|
||||
mkdir($rcptDir);
|
||||
}
|
||||
|
||||
$messageFileName = date('YmdHis') . '-' . uniqid() . '.sms';
|
||||
$fd = fopen($rcptDir . '/' . $messageFileName, 'w');
|
||||
fwrite($fd, $message);
|
||||
fclose($fd);
|
||||
|
||||
$this->logger->messageLog($username, $recipient, $message, $passwordLocations);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -3,6 +3,10 @@ namespace SmsGateway;
|
||||
|
||||
interface SenderInterface
|
||||
{
|
||||
public function setLogger(LoggerInterface $logger);
|
||||
|
||||
public function getLogger();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $recipient
|
||||
@ -10,5 +14,6 @@ interface SenderInterface
|
||||
* @return boolean true upon success. On error, throws exceptions.
|
||||
* @throws Exception Upon sending error. Gnokii output will be
|
||||
* stored in $e->message
|
||||
public function send($recipient, $message);
|
||||
*/
|
||||
public function send($username, $recipient, $message, $passwordLocations);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user