Skip to content

Commit

Permalink
[RELEASE] Create T3AM Server 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
vertexvaar committed Mar 9, 2018
0 parents commit 5f03424
Show file tree
Hide file tree
Showing 11 changed files with 534 additions and 0 deletions.
111 changes: 111 additions & 0 deletions Classes/SecurityService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php
namespace In2code\T3AM\Server;

/*
* Copyright (C) 2018 Oliver Eglseder <[email protected]>, in2code GmbH
*
* 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.
*/

use TYPO3\CMS\Core\Database\DatabaseConnection;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Saltedpasswords\Salt\SaltFactory;

/**
* Class SecurityService
*/
class SecurityService
{
/**
* @var DatabaseConnection
*/
protected $database;

/**
* SecurityService constructor.
*
* @SuppressWarnings(PHPMD.Superglobals)
*/
public function __construct()
{
$this->database = $GLOBALS['TYPO3_DB'];
}

/**
* @param DataHandler $dataHandler
*/
public function processDatamap_beforeStart(DataHandler $dataHandler)
{
if (!empty($dataHandler->datamap['tx_t3amserver_client'])) {
foreach (array_keys($dataHandler->datamap['tx_t3amserver_client']) as $uid) {
if (is_string($uid) && 0 === strpos($uid, 'NEW')) {
$dataHandler->datamap['tx_t3amserver_client'][$uid]['token'] = GeneralUtility::hmac(
GeneralUtility::generateRandomBytes(256),
'tx_t3amserver_client'
);
}
}
}
}

/**
* @param string $token
* @return bool
*/
public function isValid($token)
{
if (!is_string($token)) {
return false;
}
$where = 'token = ' . $this->database->fullQuoteStr($token, 'tx_t3amserver_client');
return (bool)$this->database->exec_SELECTcountRows('*', 'tx_t3amserver_client', $where);
}

/**
* @return array
*/
public function createEncryptionKey()
{
$config = array(
'digest_alg' => 'sha512',
'private_key_bits' => 1024,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
);

$res = openssl_pkey_new($config);
openssl_pkey_export($res, $privateKey);
$pubKey = openssl_pkey_get_details($res);

$this->database->exec_INSERTquery('tx_t3amserver_keys', ['crdate' => time(), 'key_value' => $privateKey]);
return ['pubKey' => $pubKey['key'], 'encryptionId' => $this->database->sql_insert_id()];
}

public function authUser($user, $password, $encryptionId)
{
$where = 'uid = ' . (int)$encryptionId;

$keyRow = $this->database->exec_SELECTgetSingleRow('*', 'tx_t3amserver_keys', $where);
if (!is_array($keyRow)) {
return false;
}
$this->database->exec_DELETEquery('tx_t3amserver_keys', $where);

if (!@openssl_private_decrypt(base64_decode($password), $plainPassword, $keyRow['key_value'])) {
return false;
}

$userRow = GeneralUtility::makeInstance(UserRepository::class)->getUser($user);

$saltingInstance = SaltFactory::getSaltingInstance($userRow['password']);
return $saltingInstance->checkPassword($plainPassword, $userRow['password']);
}
}
136 changes: 136 additions & 0 deletions Classes/Server.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php
namespace In2code\T3AM\Server;

/*
* Copyright (C) 2018 Oliver Eglseder <[email protected]>, in2code GmbH
*
* 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.
*/

use ReflectionException;
use ReflectionMethod;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
* Class Server
*/
class Server
{
/**
* @var SecurityService
*/
protected $tokenService = null;

/**
* @var array
*/
protected $routes = [
'check/ping' => [Server::class, 'ping'],
'user/state' => [UserRepository::class, 'getUserState'],
'user/auth' => [SecurityService::class, 'authUser'],
'user/get' => [UserRepository::class, 'getUser'],
'encryption/getKey' => [SecurityService::class, 'createEncryptionKey'],
];

/**
* Server constructor.
*/
public function __construct()
{
$this->tokenService = GeneralUtility::makeInstance(SecurityService::class);
}

public function handle()
{
try {
$data = $this->dispatch(GeneralUtility::_GET('token'), GeneralUtility::_GET('route'));
$response = ['code' => 1496395280, 'error' => false, 'message' => 'ok', 'data' => $data];
} catch (ServerException $e) {
$response = ['code' => $e->getCode(), 'error' => true, 'message' => $e->getMessage(), 'data' => []];
}

header('Content-Type: application/json');
echo json_encode($response);
}

/**
* @param string $token
* @param string $route
*
* @return array
*
* @throws ServerException
*/
protected function dispatch($token, $route)
{
if (!$this->tokenService->isValid($token)) {
throw new ServerException('Access error', 1519999361);
}

if (!is_string($route) || !isset($this->routes[$route])) {
throw new ServerException('Routing error', 1496395045);
}

list($class, $action) = $this->routes[$route];

try {
$arguments = $this->mapParametersToArguments($class, $action);
$result = call_user_func_array([GeneralUtility::makeInstance($class), $action], $arguments);
} catch (\Exception $exception) {
throw new ServerException('Exception: ' . $exception->getMessage(), 1496395387, $exception);
}

return $result;
}

/**
* @param string $class
* @param string $action
*
* @return array
*
* @throws ServerException
*/
protected function mapParametersToArguments($class, $action)
{
$arguments = [];

try {
$reflectionMethod = new ReflectionMethod($class, $action);
} catch (ReflectionException $e) {
throw new ServerException('Can not examine route target', 1520607184, $e);
}
foreach ($reflectionMethod->getParameters() as $position => $reflectionParameter) {
$parameter = $reflectionParameter->getName();
$value = GeneralUtility::_GET($parameter);

if (null === $value && !$reflectionParameter->allowsNull()) {
throw new ServerException('Missing parameter $' . $parameter, 1496395204);
} else {
if (null !== ($type = $reflectionParameter->getType())) {
settype($value, $type);
}
$arguments[$position] = $value;
}
}
return $arguments;
}

/**
* @return bool
*/
public function ping()
{
return true;
}
}

GeneralUtility::makeInstance(Server::class)->handle();
25 changes: 25 additions & 0 deletions Classes/ServerException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
namespace In2code\T3AM\Server;

/*
* Copyright (C) 2018 Oliver Eglseder <[email protected]>, in2code GmbH
*
* 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.
*/

use Exception;

/**
* Class ServerException
*/
class ServerException extends Exception
{
}
54 changes: 54 additions & 0 deletions Classes/UserRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
namespace In2code\T3AM\Server;

use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Database\DatabaseConnection;

class UserRepository
{
/**
* @var DatabaseConnection
*/
protected $connection = null;

/**
* BackendUserRepository constructor.
*
* @SuppressWarnings(PHPMD.Superglobals)
*/
public function __construct()
{
$this->connection = $GLOBALS['TYPO3_DB'];
}

/**
* @param string $user
*
* @return string
*/
public function getUserState($user)
{
$where = 'username = ' . $this->connection->fullQuoteStr($user, 'be_users');
$whereActive = $where . BackendUtility::deleteClause('be_users') . BackendUtility::BEenableFields('be_users');

if ($this->connection->exec_SELECTcountRows('*', 'be_users', $whereActive)) {
return 'okay';
}

if ($this->connection->exec_SELECTcountRows('*', 'be_users', $where)) {
return 'deleted';
}
return 'unknown';
}

/**
* @param string $user
*
* @return array
*/
public function getUser($user)
{
$where = 'username = ' . $this->connection->fullQuoteStr($user, 'be_users');
return $this->connection->exec_SELECTgetSingleRow('*', 'be_users', $where);
}
}
59 changes: 59 additions & 0 deletions Configuration/TCA/tx_t3amserver_client.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
return [
'ctrl' => [
'label' => 'identifier',
'descriptionColumn' => 'instance_notice',
'sortby' => 'tstamp',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'title' => 'T3AM Client',
'delete' => 'deleted',
'versioningWS' => false,
'hideAtCopy' => true,
'prependAtCopy' => '[copy]',
'copyAfterDuplFields' => 'instance_notice',
'searchFields' => 'token,identifier,instance_notice',
'rootLevel' => 1,
'iconfile' => 'EXT:t3am_server/ext_icon.svg',
],
'interface' => [
'always_description' => 0,
'showRecordFieldList' => 'token,identifier,instance_notice',
],
'types' => [
'1' => [
'showitem' => 'token,identifier,instance_notice',
],
],
'palettes' => [],
'columns' => [
'token' => [
'label' => 'token (save the form to generate the token)',
'config' => [
'type' => 'input',
'size' => 17,
'max' => 40,
'readOnly' => true,
],
],
'instance_notice' => [
'exclude' => true,
'label' => 'Instance description',
'config' => [
'type' => 'text',
'rows' => 5,
'cols' => 30,
],
],
'identifier' => [
'exclude' => true,
'label' => 'Instance name',
'config' => [
'type' => 'input',
'size' => 50,
'max' => 255,
],
],
],
];
Loading

0 comments on commit 5f03424

Please sign in to comment.