webgames /app/controllers/ApiController.php

Language PHP Lines 201
MD5 Hash 369ce40568f760be2cb107a1dfdc93a1 Estimated Cost $2,636 (why?)
Repository https://bitbucket.org/Crisu83/webgames View Raw File View Project SPDX
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
<?php

class ApiController extends Controller
{
	// Error codes
	const ERROR_NONE = 0;
	const ERROR_APP_KEY_INVALID = 100;
	const ERROR_TOKEN_INVALID = 200;
	const ERROR_ACTION_INVALID = 300;
	const ERROR_PARAMS_INVALID = 400;

	// HTTP status codes
	const HTTP_STATUS_OK = 200;
	const HTTP_STATUS_BAD_REQUEST = 400;
	const HTTP_STATUS_UNAUTHORIZED = 401;
	const HTTP_STATUS_INTERNAL_SERVER_ERROR = 500;

	private $_game;

	/**
	 * Outputs an access token which is required to access the api.
	 */
	public function actionRequestToken()
	{
		$token = $this->_generateToken();
		$key = $this->_resolveTokenKey();
		Yii::app()->session[$key] = $token;
		echo $token;
		Yii::app()->end();
	}

	/**
	 * Processes calls made to the api.
	 */
	public function actionCall()
	{
		$request = Yii::app()->getRequest();
		$key = $request->getParam('k');
		$query = $request->getParam('r');

		$game = $this->_loadGameByApiKey($key);

		if (!$game instanceof Game)
			$this->_endRequest(self::HTTP_STATUS_BAD_REQUEST, self::ERROR_APP_KEY_INVALID);

		$query = $this->_decryptQuery($query, $game->apiSecret);

		if (!isset($query['token']))
			$this->_endRequest(self::HTTP_STATUS_UNAUTHORIZED, self::ERROR_TOKEN_INVALID);

		$clientToken = $query['token'];
		$tokenKey = $this->_resolveTokenKey();

		if (!isset(Yii::app()->session[$tokenKey]))
			$this->_endRequest(self::HTTP_STATUS_UNAUTHORIZED, self::ERROR_TOKEN_INVALID);

		$serverToken = Yii::app()->session[$tokenKey];

		if ($clientToken !== $serverToken)
			$this->_endRequest(self::HTTP_STATUS_UNAUTHORIZED, self::ERROR_TOKEN_INVALID);

		if (!isset($query['action']))
			$this->_endRequest(self::HTTP_STATUS_BAD_REQUEST, self::ERROR_ACTION_INVALID);

		$method = $this->_resolveMethodNameByAction($query['action']);

		if (!method_exists($this, $method))
			$this->_endRequest(self::HTTP_STATUS_BAD_REQUEST, self::ERROR_ACTION_INVALID);

		$params = isset($query['params']) ? $query['params'] : array();

		$result = call_user_func_array(array($this, $method), array($params, $game));

		if ($result === false)
			$this->_endRequest(self::HTTP_STATUS_INTERNAL_SERVER_ERROR, self::ERROR_ACTION_INVALID);

		$this->_endRequest();
	}

	/**
	 * Registers a score for the active player.
	 * @param array $params the request parameters.
	 * @param Game $game the active game.
	 * @return boolean the result.
	 */
	protected function _doRegisterScore($params, $game)
	{
		if (!isset($params['score']))
			$this->_endRequest(self::HTTP_STATUS_BAD_REQUEST, self::ERROR_PARAMS_INVALID);

		$score = new Score();
		$score->gameID = $game->id;
		$score->playerID = Yii::app()->user->getPlayerID();
		$score->score = $params['score'];
		return $score->save();
	}

	/**
	 * Decrypts the given request.
	 * @param string $query the encrypted request.
	 * @param string $secret the secret key.
	 * @return array the decrypted request.
	 */
	protected function _decryptQuery($query, $secret)
	{
		return CJSON::decode($this->_decrypt($query, $secret));
	}

	/**
	 * Ends the request.
	 * @param int $statusCode the http status code.
	 * @param int $errorCode the error code.
	 * @throws CHttpException if an error occurred.
	 */
	protected function _endRequest($statusCode = self::HTTP_STATUS_OK, $errorCode = self::ERROR_NONE)
	{
		if ($errorCode !== self::ERROR_NONE)
			throw new CHttpException($statusCode, 'FAILURE. Error Code: '.$errorCode);

		echo 'SUCCESS';

		Yii::app()->end();
	}

	/**
	 * Returns the active game.
	 * @params string $key the api key.
	 * @return CActiveRecord the game.
	 */
	protected function _loadGameByApiKey($key)
	{
		if ($this->_game !== null)
			return $this->_game;
		else
		{
			$game = Game::model()->findByAttributes(array(
				'apiKey' => $key,
			));

			return $this->_game = $game;
		}
	}

	/**
	 * Encrypts a string using the given secret key.
	 * @param string $value the string to encrypt.
	 * @param string $secret the secret key.
	 * @return string the encrypted string.
	 * todo: make sure that this method actually works, it has not been tested.
	 */
	protected function _encrypt($value, $secret)
	{
		$ivSize = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
		$padding = $ivSize - (strlen((binary) $value) % $ivSize);
		$value .= str_repeat(chr($padding), $padding);
		return base64_encode(mcrypt_encrypt(MCRYPT_BLOWFISH, $secret, $value, MCRYPT_MODE_ECB));
	}

	/**
	 * Decrypts a string using the given secret key.
	 * @param string $value the string to decrypt.
	 * @param string $secret the secret key.
	 * @return string the decrypted string.
	 */
	protected function _decrypt($value, $secret)
	{
		$bytes = mcrypt_decrypt(MCRYPT_BLOWFISH, $secret, base64_decode($value), MCRYPT_MODE_ECB);
		$length = strlen($bytes);
		$padding = ord($bytes[$length - 1]);
		return substr($bytes, 0, $length - $padding);
	}

	/**
	 * Creates a unique token.
	 * @return string the token.
	 */
	protected function _generateToken()
	{
		return md5(__CLASS__.'_token_'.uniqid(true, true));
	}

	/**
	 * Returns the token key for the current player.
	 * @return string the key.
	 */
	protected function _resolveTokenKey()
	{
		return __CLASS__.'_token_'.Yii::app()->user->getPlayerID();
	}

	/**
	 * Returns the method name for the given action.
	 * @param string $name the action name.
	 * @return string the method name.
	 */
	protected function _resolveMethodNameByAction($action)
	{
		return '_do'.ucfirst($action);
	}
}
Back to Top