Issues (524)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

code/model/jobs/DNDataTransfer.php (12 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Class representing a single data transfer in a project,
5
 * which can include a database export, an archive of all assets, or both.
6
 *
7
 * It can be one of two directions:
8
 * - Backup: Package up data on an environment and store it in a local file
9
 * - Restore: Transfer data from a local file into an environment, extract assets and/or restore a database
10
 *
11
 * The choice of database and/or assets is represented in the "Mode".
12
 * There's always one file archive involved (stored as the has_one "ArchiveFile") on the local Deploynaut environment.
13
 *
14
 * Each transfer is executed by a Resque job, so the model also contains
15
 * a reference to a Resque token (which might still be in progress).
16
 *
17
 * The "Environment" points to the source or target involved.
18
 *
19
 * @property string $ResqueToken
20
 * @property string $Status
21
 * @property string $Direction
22
 * @property string $Mode
23
 * @property string $Origin
24
 *
25
 * @method DNEnvironment Environment()
26
 * @property int EnvironmentID
27
 * @method Member Author()
28
 * @property int AuthorID
29
 * @method DNDataArchive DataArchive()
30
 * @property int DataArchiveID
31
 * @method DNDataTransfer BackupDataTransfer()
32
 * @property int BackupDataTransferID
33
 */
34
class DNDataTransfer extends DataObject {
0 ignored issues
show
The property $has_one is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
The property $singular_name is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
The property $plural_name is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
The property $summary_fields is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
The property $searchable_fields is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
35
36
	private static $db = array(
37
		"ResqueToken" => "Varchar(255)",
38
		// Observe that this is not the same as Resque status, since ResqueStatus is not persistent.
39
		"Status" => "Enum('Queued, Started, Finished, Failed, n/a', 'n/a')",
40
		"Direction" => "Enum('get, push', 'get')",
41
		"Mode" => "Enum('all, assets, db', '')",
42
		"Origin" => "Enum('EnvironmentTransfer,ManualUpload', 'EnvironmentTransfer')",
43
		"IncludeResampled" => "Boolean",
44
	);
45
46
	private static $has_one = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
47
		"Environment" => "DNEnvironment",
48
		"Author" => "Member",
49
		"DataArchive" => "DNDataArchive",
50
		"BackupDataTransfer" => "DNDataTransfer" // denotes an automated backup done for a push of this data transfer
51
	);
52
53
	private static $singular_name = 'Data Transfer';
0 ignored issues
show
The property $singular_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
54
55
	private static $plural_name = 'Data Transfers';
56
57
	private static $summary_fields = array(
58
		'Created' => 'Created',
59
		'Author.Title' => 'Author',
60
		'Environment.Project.Name' => 'Project',
61
		'Environment.Name' => 'Environment',
62
		'Status' => 'Status',
63
		'Origin' => 'Origin',
64
		'IncludeResampled.Nice' => 'Included Resampled?',
65
	);
66
67
	private static $searchable_fields = array(
68
		'Environment.Project.Name' => array(
69
			'title' => 'Project',
70
		),
71
		'Environment.Name' => array(
72
			'title' => 'Environment',
73
		),
74
		'Status' => array(
75
			'title' => 'Status',
76
		),
77
		'Origin' => array(
78
			'title' => 'Origin',
79
		),
80
		'Mode' => array(
81
			'title' => 'Mode',
82
		),
83
		'Direction' => array(
84
			'title' => 'Direction',
85
		),
86
	);
87
88
	/**
89
	 * When running the transfer, should a backup be performed before pushing the data?
90
	 * @var bool
91
	 */
92
	protected $backupBeforePush = true;
93
94
	/**
95
	 * @param int $int
96
	 * @return string
97
	 */
98 View Code Duplication
	public static function map_resque_status($int) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
99
		$remap = array(
100
			Resque_Job_Status::STATUS_WAITING => "Queued",
101
			Resque_Job_Status::STATUS_RUNNING => "Running",
102
			Resque_Job_Status::STATUS_FAILED => "Failed",
103
			Resque_Job_Status::STATUS_COMPLETE => "Complete",
104
			false => "Invalid",
105
		);
106
		return $remap[$int];
107
	}
108
109
	/**
110
	 * @param boolean $value
111
	 */
112
	public function setBackupBeforePush($value) {
113
		$this->backupBeforePush = $value;
114
	}
115
116
	public function getTitle() {
117
		return $this->dbObject('Created')->Nice() . " (Status: {$this->Status})";
118
	}
119
120
	public function Link() {
121
		return Controller::join_links($this->Environment()->Project()->Link(), 'transfer', $this->ID);
122
	}
123
124
	public function LogLink() {
125
		return Controller::join_links($this->Link(), 'log');
126
	}
127
128
	public function getDefaultSearchContext() {
129
		$context = parent::getDefaultSearchContext();
130
		$context->getFields()->dataFieldByName('Status')->setHasEmptyDefault(true);
131
		$context->getFields()->dataFieldByName('Origin')->setHasEmptyDefault(true);
132
133
		return $context;
134
	}
135
136
	public function getCMSFields() {
137
		$fields = parent::getCMSFields();
138
		$fields->removeByName('EnvironmentID');
139
		$fields->removeByName('ArchiveFile');
140
		$fields->addFieldsToTab(
141
			'Root.Main',
142
			array(
143
				new ReadonlyField('ProjectName', 'Project', $this->Environment()->Project()->Name),
144
				new ReadonlyField('EnvironmentName', 'Environment', $this->Environment()->Name),
145
				new ReadonlyField(
146
					'DataArchive',
147
					'Archive File',
148
					sprintf(
149
						'<a href="%s">%s</a>',
150
						$this->DataArchive()->ArchiveFile()->AbsoluteURL,
151
						$this->DataArchive()->ArchiveFile()->Filename
152
					)
153
				),
154
			)
155
		);
156
		$fields = $fields->makeReadonly();
157
158
		return $fields;
159
	}
160
161
	/**
162
	 * Queue a transfer job
163
	 */
164
	public function start() {
165
		$env = $this->Environment();
166
		$log = $this->log();
167
168
		$args = array(
169
			'dataTransferID' => $this->ID,
170
			'logfile' => $this->logfile(),
171
			'backupBeforePush' => $this->backupBeforePush,
172
			'includeResampled' => $this->IncludeResampled,
0 ignored issues
show
The property IncludeResampled does not exist on object<DNDataTransfer>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
173
		);
174
175
		if(!$this->AuthorID) {
176
			$this->AuthorID = Member::currentUserID();
177
		}
178
179 View Code Duplication
		if($this->AuthorID) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
			$author = $this->Author();
181
			$message = sprintf(
182
				'Data transfer on %s (%s, %s) initiated by %s (%s), with IP address %s',
183
				$env->getFullName(),
184
				$this->Direction,
185
				$this->Mode,
186
				$author->getName(),
187
				$author->Email,
188
				Controller::curr()->getRequest()->getIP()
189
			);
190
			$log->write($message);
191
		}
192
193
		$token = Resque::enqueue('snapshot', 'DataTransferJob', $args, true);
194
		$this->ResqueToken = $token;
195
		$this->write();
196
197
		$message = sprintf('Data transfer queued as job %s', $token);
198
		$log->write($message);
199
	}
200
201
	/**
202
	 * @param Member|null $member
203
	 * @return bool
204
	 */
205
	public function canView($member = null) {
206
		return $this->Environment()->canView($member);
207
	}
208
209
	/**
210
	 * Return a path to the log file.
211
	 * @return string
212
	 */
213
	protected function logfile() {
214
		return sprintf(
215
			'%s.datatransfer.%s.log',
216
			$this->Environment()->getFullName('.'),
217
			$this->ID
218
		);
219
	}
220
221
	/**
222
	 * @return \DeploynautLogFile
223
	 */
224
	public function log() {
225
		return new DeploynautLogFile($this->logfile());
226
	}
227
228
	/**
229
	 * @return string
230
	 */
231
	public function LogContent() {
232
		return $this->log()->content();
233
	}
234
235
	public function getDescription() {
236
		$envName = $this->Environment()->getFullName();
237
		if($this->Direction == 'get') {
238
			if($this->Origin == 'ManualUpload') {
239
				$description = 'Manual upload of ' . $this->getModeNice() . ' to ' . $envName;
240
			} elseif($this->IsBackupDataTransfer()) {
241
				$description = 'Automated backup of ' . $this->getModeNice() . ' from ' . $envName;
242
			} else {
243
				$description = 'Backup of ' . $this->getModeNice() . ' to ' . $envName;
244
			}
245
		} else {
246
			$description = 'Restore ' . $this->getModeNice() . ' to ' . $envName;
247
		}
248
249
		return $description;
250
	}
251
252
	public function getModeNice() {
253
		if($this->Mode == 'all') {
254
			return 'database and assets';
255
		} else {
256
			return $this->Mode;
257
		}
258
	}
259
260
	/**
261
	 * Is this transfer an automated backup prior to a push transfer or deployment?
262
	 * @return boolean
263
	 */
264
	public function IsBackupDataTransfer() {
265
		$deploymentBackup = DB::query(sprintf(
266
			'SELECT COUNT("ID") FROM "DNDeployment" WHERE "BackupDataTransferID" = %d',
267
			$this->ID
268
		))->value();
269
		if ($deploymentBackup) {
270
			return true;
271
		}
272
273
		$transferBackup = DB::query(sprintf(
274
			'SELECT COUNT("ID") FROM "DNDataTransfer" WHERE "BackupDataTransferID" = %d',
275
			$this->ID
276
		))->value();
277
		if ($transferBackup) {
278
			return true;
279
		}
280
281
		return false;
282
	}
283
284
	/**
285
	 * Returns the status of the resque job
286
	 *
287
	 * @return string
288
	 */
289 View Code Duplication
	public function ResqueStatus() {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
290
		$status = new Resque_Job_Status($this->ResqueToken);
0 ignored issues
show
It seems like $this->ResqueToken can also be of type false; however, Resque_Job_Status::__construct() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
291
		$statusCode = $status->get();
292
		// The Resque job can no longer be found, fallback to the DNDataTransfer.Status
293
		if($statusCode === false) {
294
			// Translate from the DNDataTransfer.Status to the Resque job status for UI purposes
295
			switch($this->Status) {
296
				case 'Finished':
297
					return 'Complete';
298
				case 'Started':
299
					return 'Running';
300
				default:
301
					return $this->Status;
302
			}
303
		}
304
		return self::map_resque_status($statusCode);
305
	}
306
307
}
308