diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js index 39f769e0..0855e6e7 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js @@ -153,7 +153,7 @@ class AdminPanelAdvancedSettings extends React.Component { ModalContainer.closeModal(); API.call({ path: '/system/add-api-key', - data: {name} + data: {name, type: 'REGISTRATION'} }).then(this.getAllKeys.bind(this)); } @@ -177,7 +177,7 @@ class AdminPanelAdvancedSettings extends React.Component { onRetrieveSuccess(result) { this.setState({ - APIKeys: result.data, + APIKeys: result.data.filter(key => key['type'] === 'REGISTRATION'), selectedAPIKey: -1 }); } diff --git a/server/controllers/system/add-api-key.php b/server/controllers/system/add-api-key.php index 38ef0861..fbb34107 100755 --- a/server/controllers/system/add-api-key.php +++ b/server/controllers/system/add-api-key.php @@ -14,10 +14,12 @@ use Respect\Validation\Validator as DataValidator; * @apiPermission staff3 * * @apiParam {String} name Name of the new APIKey. + * @apiParam {String} type Type of APIKey: "REGISTRATION" or "TICKET_CREATE" * * @apiUse NO_PERMISSION * @apiUse INVALID_NAME * @apiUse NAME_ALREADY_USED + * @apiUse INVALID_API_KEY_TYPE * * @apiSuccess {String} data Token of the APIKey. * @@ -34,6 +36,10 @@ class AddAPIKeyController extends Controller { 'name' => [ 'validation' => DataValidator::length(2, 55)->alnum(), 'error' => ERRORS::INVALID_NAME + ], + 'type' => [ + 'validation' => DataValidator::in(APIKey::TYPES), + 'error' => ERRORS::INVALID_API_KEY_TYPE ] ] ]; @@ -43,6 +49,7 @@ class AddAPIKeyController extends Controller { $apiInstance = new APIKey(); $name = Controller::request('name'); + $type = Controller::request('type'); $keyInstance = APIKey::getDataStore($name, 'name'); @@ -51,7 +58,8 @@ class AddAPIKeyController extends Controller { $apiInstance->setProperties([ 'name' => $name, - 'token' => $token + 'token' => $token, + 'type' => $type, ]); $apiInstance->store(); diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php index 1ea18790..6fb76b28 100755 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -75,7 +75,7 @@ class CreateController extends Controller { if(!Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) { $validations['permission'] = 'any'; $validations['requestData']['captcha'] = [ - 'validation' => DataValidator::captcha(), + 'validation' => DataValidator::captcha(APIKey::TICKET_CREATE), 'error' => ERRORS::INVALID_CAPTCHA ]; $validations['requestData']['email'] = [ diff --git a/server/controllers/user/signup.php b/server/controllers/user/signup.php index ec6736cb..12184a0b 100755 --- a/server/controllers/user/signup.php +++ b/server/controllers/user/signup.php @@ -72,7 +72,7 @@ class SignUpController extends Controller { if(!$this->csvImported) { $validations['requestData']['captcha'] = [ - 'validation' => DataValidator::captcha(), + 'validation' => DataValidator::captcha(APIKey::REGISTRATION), 'error' => ERRORS::INVALID_CAPTCHA ]; } @@ -103,6 +103,10 @@ class SignUpController extends Controller { throw new RequestException(ERRORS::NO_PERMISSION); } + if(!$apiKey->isNull() && $apiKey->type !== APIKey::REGISTRATION) { + throw new RequestException(ERRORS::INVALID_API_KEY_TYPE); + } + $userId = $this->createNewUserAndRetrieveId(); if(MailSender::getInstance()->isConnected()) { diff --git a/server/data/ERRORS.php b/server/data/ERRORS.php index 2e56b685..34338349 100755 --- a/server/data/ERRORS.php +++ b/server/data/ERRORS.php @@ -251,6 +251,10 @@ * @apiDefine INVALID_COLOR * @apiError {String} INVALID_COLOR The color should be in hexadecimal, preceded by a '#' */ +/** + * @apiDefine INVALID_API_KEY_TYPE + * @apiError {String} INVALID_API_KEY_TYPE Api key type is not one of the availables + */ class ERRORS { const INVALID_CREDENTIALS = 'INVALID_CREDENTIALS'; @@ -326,4 +330,5 @@ class ERRORS { const INVALID_CUSTOM_FIELD_OPTION = 'INVALID_CUSTOM_FIELD_OPTION'; const UNAVAILABLE_STATS = 'UNAVAILABLE_STATS'; const INVALID_COLOR = 'INVALID_COLOR'; + const INVALID_API_KEY_TYPE = 'INVALID_API_KEY_TYPE'; } diff --git a/server/libs/validations/captcha.php b/server/libs/validations/captcha.php index 7ac805c2..e37ca9fa 100755 --- a/server/libs/validations/captcha.php +++ b/server/libs/validations/captcha.php @@ -5,12 +5,22 @@ namespace CustomValidations; use Respect\Validation\Rules\AbstractRule; class Captcha extends AbstractRule { + private $dataStoreName; + + public function __construct($apiKeyType = '') { + if (in_array($apiKeyType, \APIKey::TYPES)) { + $this->apiKeyType = $apiKeyType; + } else if($apiKeyType) { + throw new \Exception(\ERRORS::INVALID_API_KEY_TYPE); + } + } public function validate($reCaptchaResponse) { $reCaptchaPrivateKey = \Setting::getSetting('recaptcha-private')->getValue(); $apiKey = \APIKey::getDataStore(\Controller::request('apiKey'), 'token'); - if (!$reCaptchaPrivateKey || !$apiKey->isNull()) return true; + if (!$reCaptchaPrivateKey) return true; + if (!$apiKey->isNull() && $apiKey->type === $apiKeyType) return true; $reCaptcha = new \ReCaptcha\ReCaptcha($reCaptchaPrivateKey); $reCaptchaValidation = $reCaptcha->verify($reCaptchaResponse, $_SERVER['REMOTE_ADDR']); diff --git a/server/models/APIKey.php b/server/models/APIKey.php index 436b2b14..9cb1c4ff 100755 --- a/server/models/APIKey.php +++ b/server/models/APIKey.php @@ -9,18 +9,29 @@ class APIKey extends DataStore { const TABLE = 'apikey'; + const REGISTRATION = 'REGISTRATION'; + const TICKET_CREATE = 'TICKET_CREATE'; + const TYPES = [APIKey::REGISTRATION, APIKey::TICKET_CREATE]; public static function getProps() { return [ 'name', - 'token' + 'token', + 'type' + ]; + } + + public function getDefaultProps() { + return [ + 'type' => APIKey::REGISTRATION ]; } public function toArray() { return [ 'name' => $this->name, - 'token' => $this->token + 'token' => $this->token, + 'type' => $this->type ]; } } \ No newline at end of file diff --git a/server/tests/__mocks__/APIKeyMock.php b/server/tests/__mocks__/APIKeyMock.php index 7ef32d77..70f5d0d8 100755 --- a/server/tests/__mocks__/APIKeyMock.php +++ b/server/tests/__mocks__/APIKeyMock.php @@ -2,6 +2,10 @@ include_once 'tests/__mocks__/NullDataStoreMock.php'; class APIKey extends \Mock { + const REGISTRATION = 'REGISTRATION'; + const TICKET_CREATE = 'TICKET_CREATE'; + const TYPES = [APIKey::REGISTRATION, APIKey::TICKET_CREATE]; + public static $functionList = array(); public static function initStubs() { diff --git a/tests/init.rb b/tests/init.rb index e86faea2..eb082cb6 100644 --- a/tests/init.rb +++ b/tests/init.rb @@ -56,11 +56,11 @@ require './system/edit-department.rb' require './system/delete-department.rb' require './staff/last-events.rb' # require './system/mail-templates.rb' -require './system/disable-registration.rb' -require './system/enable-registration.rb' require './system/add-api-key.rb' require './system/delete-api-key.rb' require './system/get-api-keys.rb' +require './system/disable-registration.rb' +require './system/enable-registration.rb' require './system/file-upload-download.rb' require './system/csv-import.rb' require './ticket/create-tag.rb' diff --git a/tests/scripts.rb b/tests/scripts.rb index e0c7e24c..2e7a7715 100644 --- a/tests/scripts.rb +++ b/tests/scripts.rb @@ -97,11 +97,12 @@ class Scripts result['data'] end - def self.createAPIKey(name) + def self.createAPIKey(name, type) request('/system/add-api-key', { csrf_userid: $csrf_userid, csrf_token: $csrf_token, - name: name + name: name, + type: type }) end diff --git a/tests/system/add-api-key.rb b/tests/system/add-api-key.rb index cf8c86d5..ecf2f431 100644 --- a/tests/system/add-api-key.rb +++ b/tests/system/add-api-key.rb @@ -1,30 +1,44 @@ describe'system/add-api-key' do - request('/user/logout') - Scripts.login($staff[:email], $staff[:password], true) + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) - it 'should add API key' do - result= request('/system/add-api-key', { - csrf_userid: $csrf_userid, - csrf_token: $csrf_token, - name: 'new API' - }) + it 'should add API key' do + result= request('/system/add-api-key', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + name: 'new API', + type: 'REGISTRATION' + }) - (result['status']).should.equal('success') + (result['status']).should.equal('success') - row = $database.getRow('apikey', 1, 'id') + row = $database.getRow('apikey', 1, 'id') - (row['name']).should.equal('new API') - (result['data']).should.equal(row['token']) + (row['name']).should.equal('new API') + (result['data']).should.equal(row['token']) + end - end - it 'should not add API key' do - result= request('/system/add-api-key', { - csrf_userid: $csrf_userid, - csrf_token: $csrf_token, - name: 'new API' - }) + it 'should not add API key if name already used' do + result= request('/system/add-api-key', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + name: 'new API', + type: 'REGISTRATION' + }) - (result['status']).should.equal('fail') - (result['message']).should.equal('NAME_ALREADY_USED') - end + (result['status']).should.equal('fail') + (result['message']).should.equal('NAME_ALREADY_USED') + end + + it 'should not add API key if invalid type is used' do + result= request('/system/add-api-key', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + name: 'new API2', + type: 'REGISTRATON' + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_API_KEY_TYPE') + end end diff --git a/tests/system/disable-registration.rb b/tests/system/disable-registration.rb index 13e4c06c..539a29dc 100644 --- a/tests/system/disable-registration.rb +++ b/tests/system/disable-registration.rb @@ -1,6 +1,7 @@ describe'/system/disable-registration' do request('/user/logout') Scripts.login($staff[:email], $staff[:password], true) + api_key = Scripts.createAPIKey('registrationKey', 'REGISTRATION')['data'] it 'should not disable registration if password is not correct' do result= request('/system/disable-registration', { @@ -17,7 +18,7 @@ describe'/system/disable-registration' do end it 'should disable registration' do - result= request('/system/disable-registration', { + result = request('/system/disable-registration', { csrf_userid: $csrf_userid, csrf_token: $csrf_token, password: $staff[:password] @@ -31,13 +32,23 @@ describe'/system/disable-registration' do end it 'should not create user in database if registration is false' do - response = request('/user/signup', { + result = request('/user/signup', { :name => 'ponzio', :email => 'jc@ponziolandia.com', :password => 'tequila' }) - (response['status']).should.equal('fail') + (result['status']).should.equal('fail') + (result['message']).should.equal('NO_PERMISSION') + end + it 'should create user if using api key' do + result = request('/user/signup', { + :name => 'ponzio', + :email => 'jc@ponziolandia.com', + :password => 'tequila', + :apiKey => api_key + }) + (result['status']).should.equal('success') end end diff --git a/tests/system/disable-user-system.rb b/tests/system/disable-user-system.rb index 9ae8dd15..7107ecc3 100644 --- a/tests/system/disable-user-system.rb +++ b/tests/system/disable-user-system.rb @@ -17,7 +17,7 @@ describe'system/disable-user-system' do row = $database.getRow('user', 1, 'id') (row).should.equal(nil) - numberOftickets= $database.query("SELECT * FROM ticket WHERE author_id IS NULL AND author_email IS NOT NULL AND author_name IS NOT NULL") + numberOftickets = $database.query("SELECT * FROM ticket WHERE author_id IS NULL AND author_email IS NOT NULL AND author_name IS NOT NULL") (numberOftickets.num_rows).should.equal(51) @@ -148,6 +148,21 @@ describe'system/disable-user-system' do (ticket['author_staff_id']).should.equal('1') end + it 'should be able to create a ticket using api' do + api_key = Scripts.createAPIKey('ticketCreateKey', 'TICKET_CREATE')['data'] + request('/user/logout') + result = request('/ticket/create', { + email: 'fromapi@testemail.com', + name: 'Random user', + title: 'created by api', + content: 'this ticket was created using anapi key while user system is disabled', + departmentId: 1, + language: 'en', + apiKey: api_key + }) + (result['status']).should.equal('success') + end + it 'should not disable the user system if it is already disabled 'do request('/user/logout') Scripts.login($staff[:email], $staff[:password], true) @@ -205,7 +220,7 @@ describe'system/disable-user-system' do numberOftickets= $database.query("SELECT * FROM ticket WHERE author_email IS NULL AND author_name IS NULL AND author_id IS NOT NULL" ) - (numberOftickets.num_rows).should.equal(53) + (numberOftickets.num_rows).should.equal(54) end it 'should not enable the user system' do diff --git a/tests/system/get-api-keys.rb b/tests/system/get-api-keys.rb index 518dc818..e6c62900 100644 --- a/tests/system/get-api-keys.rb +++ b/tests/system/get-api-keys.rb @@ -1,26 +1,25 @@ describe'system/get-api-keys' do - request('/user/logout') - Scripts.login($staff[:email], $staff[:password], true) + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) - it 'should get all API keys' do - Scripts.createAPIKey('namekey1') - Scripts.createAPIKey('namekey2') - Scripts.createAPIKey('namekey3') - Scripts.createAPIKey('namekey4') - Scripts.createAPIKey('namekey5') - - result = request('/system/get-api-keys', { - csrf_userid: $csrf_userid, - csrf_token: $csrf_token, - }) + it 'should get all API keys' do + Scripts.createAPIKey('namekey1', 'REGISTRATION') + Scripts.createAPIKey('namekey2', 'REGISTRATION') + Scripts.createAPIKey('namekey3', 'REGISTRATION') + Scripts.createAPIKey('namekey4', 'REGISTRATION') + Scripts.createAPIKey('namekey5', 'REGISTRATION') + + result = request('/system/get-api-keys', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + }) - (result['status']).should.equal('success') - (result['data'][0]['name']).should.equal('namekey1') - (result['data'][1]['name']).should.equal('namekey2') - (result['data'][2]['name']).should.equal('namekey3') - (result['data'][3]['name']).should.equal('namekey4') - (result['data'][4]['name']).should.equal('namekey5') - - end + (result['status']).should.equal('success') + (result['data'][0]['name']).should.equal('namekey1') + (result['data'][1]['name']).should.equal('namekey2') + (result['data'][2]['name']).should.equal('namekey3') + (result['data'][3]['name']).should.equal('namekey4') + (result['data'][4]['name']).should.equal('namekey5') + end end