Project

General

Profile

Download (11.6 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	edit.php
4
*/
5
/* ====================================================================
6
 *	Copyright (c)  2004-2015  Electric Sheep Fencing, LLC. All rights reserved.
7
 *
8
 *	Redistribution and use in source and binary forms, with or without modification,
9
 *	are permitted provided that the following conditions are met:
10
 *
11
 *	1. Redistributions of source code must retain the above copyright notice,
12
 *		this list of conditions and the following disclaimer.
13
 *
14
 *	2. Redistributions in binary form must reproduce the above copyright
15
 *		notice, this list of conditions and the following disclaimer in
16
 *		the documentation and/or other materials provided with the
17
 *		distribution.
18
 *
19
 *	3. All advertising materials mentioning features or use of this software
20
 *		must display the following acknowledgment:
21
 *		"This product includes software developed by the pfSense Project
22
 *		 for use in the pfSense software distribution. (http://www.pfsense.org/).
23
 *
24
 *	4. The names "pfSense" and "pfSense Project" must not be used to
25
 *		 endorse or promote products derived from this software without
26
 *		 prior written permission. For written permission, please contact
27
 *		 coreteam@pfsense.org.
28
 *
29
 *	5. Products derived from this software may not be called "pfSense"
30
 *		nor may "pfSense" appear in their names without prior written
31
 *		permission of the Electric Sheep Fencing, LLC.
32
 *
33
 *	6. Redistributions of any form whatsoever must retain the following
34
 *		acknowledgment:
35
 *
36
 *	"This product includes software developed by the pfSense Project
37
 *	for use in the pfSense software distribution (http://www.pfsense.org/).
38
 *
39
 *	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
40
 *	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41
 *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42
 *	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
43
 *	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44
 *	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45
 *	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46
 *	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
 *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48
 *	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49
 *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50
 *	OF THE POSSIBILITY OF SUCH DAMAGE.
51
 *
52
 *	====================================================================
53
 *
54
 */
55

    
56
##|+PRIV
57
##|*IDENT=page-diagnostics-edit
58
##|*NAME=Diagnostics: Edit File
59
##|*DESCR=Allow access to the 'Diagnostics: Edit File' page.
60
##|*MATCH=edit.php*
61
##|*MATCH=browser.php*
62
##|*MATCH=filebrowser/browser.php*
63
##|-PRIV
64

    
65
$pgtitle = array(gettext("Diagnostics"), gettext("Edit file"));
66
require("guiconfig.inc");
67

    
68
if ($_POST['action']) {
69
	$button_html = '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>';
70
	$alert_danger_html = '<div class="alert alert-danger" role="alert">' . $button_html;
71
	$alert_success_html = '<div class="alert alert-success" role="alert">' . $button_html;
72
	switch ($_POST['action']) {
73
		case 'load':
74
			if (strlen($_POST['file']) < 1) {
75
				print('|5|' . $alert_danger_html . gettext("No file name specified") . '</div>' . '|');
76
			} elseif (is_dir($_POST['file'])) {
77
				print('|4|' . $alert_danger_html . gettext("Loading a directory is not supported") . '</div>' . '|');
78
			} elseif (!is_file($_POST['file'])) {
79
				print('|3|' . $alert_danger_html . gettext("File does not exist or is not a regular file") . '</div>' . '|');
80
			} else {
81
				$data = file_get_contents(urldecode($_POST['file']));
82
				if ($data === false) {
83
					print('|1|' . $alert_danger_html . gettext("Failed to read file") . '</div>' . '|');
84
				} else {
85
					$data = base64_encode($data);
86
					print("|0|{$_POST['file']}|{$data}|");
87
				}
88
			}
89
			exit;
90

    
91
		case 'save':
92
			if (strlen($_POST['file']) < 1) {
93
				print('|' . $alert_danger_html . gettext("No file name specified") . '</div>' . '|');
94
			} else {
95
				conf_mount_rw();
96
				$_POST['data'] = str_replace("\r", "", base64_decode($_POST['data']));
97
				$ret = file_put_contents($_POST['file'], $_POST['data']);
98
				conf_mount_ro();
99
				if ($_POST['file'] == "/conf/config.xml" || $_POST['file'] == "/cf/conf/config.xml") {
100
					if (file_exists("/tmp/config.cache")) {
101
						unlink("/tmp/config.cache");
102
					}
103
					disable_security_checks();
104
				}
105
				if ($ret === false) {
106
					print('|' . $alert_danger_html . gettext("Failed to write file") . '</div>' . '|');
107
				} elseif ($ret != strlen($_POST['data'])) {
108
					print('|' . $alert_danger_html . gettext("Error while writing file") . '</div>' . '|');
109
				} else {
110
					print('|' . $alert_success_html . gettext("File saved successfully") . '</div>' . '|');
111
				}
112
			}
113
			exit;
114
	}
115
	exit;
116
}
117

    
118
require("head.inc");
119
?>
120
<!-- file status box -->
121
<div style="display:none; background:#eeeeee;" id="fileStatusBox">
122
	<strong id="fileStatus"></strong>
123
</div>
124

    
125
<div class="panel panel-default">
126
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Save / Load a file from the filesystem")?></h2></div>
127
	<div class="panel-body">
128
		<div class="content">
129
			<form>
130
				<input type="text" class="form-control" id="fbTarget"/>
131
				<input type="button" class="btn btn-default btn-sm"	  onclick="loadFile();" value="<?=gettext('Load')?>" />
132
				<input type="button" class="btn btn-default btn-sm"	  id="fbOpen"		   value="<?=gettext('Browse')?>" />
133
				<input type="button" class="btn btn-default btn-sm"	  onclick="saveFile();" value="<?=gettext('Save')?>" />
134
				<span class="pull-right">
135
					<button id="btngoto" class="btn btn-default btn-sm"><?=gettext("GoTo Line #")?></button> <input type="number" id="gotoline" width="6"></input>
136
				</span>
137
			</form>
138

    
139
			<div id="fbBrowser" style="display:none; border:1px dashed gray; width:98%;"></div>
140

    
141
			<div style="background:#eeeeee;" id="fileOutput">
142
				<script type="text/javascript">
143
				//<![CDATA[
144
				window.onload=function() {
145
					document.getElementById("fileContent").wrap='off';
146
				}
147
				//]]>
148
				</script>
149
				<textarea id="fileContent" name="fileContent" class="form-control" rows="30" cols=""></textarea>
150
			</div>
151
		</div>
152
	</div>
153
</div>
154

    
155
<script type="text/javascript">
156
//<![CDATA[
157
	events.push(function(){
158

    
159
		function showLine(tarea, lineNum) {
160

    
161
			lineNum--; // array starts at 0
162
			var lines = tarea.value.split("\n");
163

    
164
			// calculate start/end
165
			var startPos = 0, endPos = tarea.value.length;
166
			for(var x = 0; x < lines.length; x++) {
167
				if(x == lineNum) {
168
					break;
169
				}
170
				startPos += (lines[x].length+1);
171

    
172
			}
173

    
174
			var endPos = lines[lineNum].length+startPos;
175

    
176
			// do selection
177
			// Chrome / Firefox
178

    
179
			if(typeof(tarea.selectionStart) != "undefined") {
180
				tarea.focus();
181
				tarea.selectionStart = startPos;
182
				tarea.selectionEnd = endPos;
183
				return true;
184
			}
185

    
186
			// IE
187
			if (document.selection && document.selection.createRange) {
188
				tarea.focus();
189
				tarea.select();
190
				var range = document.selection.createRange();
191
				range.collapse(true);
192
				range.moveEnd("character", endPos);
193
				range.moveStart("character", startPos);
194
				range.select();
195
				return true;
196
			}
197

    
198
			return false;
199
		}
200

    
201
		$("#btngoto").prop('type','button');
202

    
203
		$('#btngoto').click(function() {
204
			var tarea = document.getElementById("fileContent");
205
			showLine(tarea, $('#gotoline').val());
206
		});
207
	});
208

    
209
	function loadFile() {
210
		$("#fileStatus").html("");
211
		$("#fileStatusBox").show(500);
212
		$.ajax(
213
			"<?=$_SERVER['SCRIPT_NAME']?>", {
214
				type: "post",
215
				data: "action=load&file=" + $("#fbTarget").val(),
216
				complete: loadComplete
217
			}
218
		);
219
	}
220

    
221
	function loadComplete(req) {
222
		$("#fileContent").show(1000);
223
		var values = req.responseText.split("|");
224
		values.shift(); values.pop();
225

    
226
		if (values.shift() == "0") {
227
			var file = values.shift();
228
			var fileContent = window.atob(values.join("|"));
229

    
230
			$("#fileContent").val(fileContent);
231
		} else {
232
			$("#fileStatus").html(values[0]);
233
			$("#fileContent").val("");
234
		}
235

    
236
		$("#fileContent").show(1000);
237
	}
238

    
239
	function saveFile(file) {
240
		$("#fileStatus").html("");
241
		$("#fileStatusBox").show(500);
242

    
243
		var fileContent = Base64.encode($("#fileContent").val());
244
		fileContent = fileContent.replace(/\+/g, "%2B");
245

    
246
		$.ajax(
247
			"<?=$_SERVER['SCRIPT_NAME']?>", {
248
				type: "post",
249
				data: "action=save&file=" + $("#fbTarget").val() +
250
							"&data=" + fileContent,
251
				complete: function(req) {
252
					var values = req.responseText.split("|");
253
					$("#fileStatus").html(values[1]);
254
				}
255
			}
256
		);
257
	}
258

    
259
/**
260
 *
261
 *	Base64 encode / decode
262
 *	http://www.webtoolkit.info/
263
 *	http://www.webtoolkit.info/licence
264
 **/
265

    
266
var Base64 = {
267

    
268
	// private property
269
	_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
270

    
271
	// public method for encoding
272
	encode : function (input) {
273
		var output = "";
274
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
275
		var i = 0;
276

    
277
		input = Base64._utf8_encode(input);
278

    
279
		while (i < input.length) {
280

    
281
			chr1 = input.charCodeAt(i++);
282
			chr2 = input.charCodeAt(i++);
283
			chr3 = input.charCodeAt(i++);
284

    
285
			enc1 = chr1 >> 2;
286
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
287
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
288
			enc4 = chr3 & 63;
289

    
290
			if (isNaN(chr2)) {
291
				enc3 = enc4 = 64;
292
			} else if (isNaN(chr3)) {
293
				enc4 = 64;
294
			}
295

    
296
			output = output +
297
			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
298
			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
299

    
300
		}
301

    
302
		return output;
303
	},
304

    
305
	// public method for decoding
306
	decode : function (input) {
307
		var output = "";
308
		var chr1, chr2, chr3;
309
		var enc1, enc2, enc3, enc4;
310
		var i = 0;
311

    
312
		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
313

    
314
		while (i < input.length) {
315

    
316
			enc1 = this._keyStr.indexOf(input.charAt(i++));
317
			enc2 = this._keyStr.indexOf(input.charAt(i++));
318
			enc3 = this._keyStr.indexOf(input.charAt(i++));
319
			enc4 = this._keyStr.indexOf(input.charAt(i++));
320

    
321
			chr1 = (enc1 << 2) | (enc2 >> 4);
322
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
323
			chr3 = ((enc3 & 3) << 6) | enc4;
324

    
325
			output = output + String.fromCharCode(chr1);
326

    
327
			if (enc3 != 64) {
328
				output = output + String.fromCharCode(chr2);
329
			}
330
			if (enc4 != 64) {
331
				output = output + String.fromCharCode(chr3);
332
			}
333

    
334
		}
335

    
336
		output = Base64._utf8_decode(output);
337

    
338
		return output;
339

    
340
	},
341

    
342
	// private method for UTF-8 encoding
343
	_utf8_encode : function (string) {
344
		string = string.replace(/\r\n/g,"\n");
345
		var utftext = "";
346

    
347
		for (var n = 0; n < string.length; n++) {
348

    
349
			var c = string.charCodeAt(n);
350

    
351
			if (c < 128) {
352
				utftext += String.fromCharCode(c);
353
			} else if ((c > 127) && (c < 2048)) {
354
				utftext += String.fromCharCode((c >> 6) | 192);
355
				utftext += String.fromCharCode((c & 63) | 128);
356
			} else {
357
				utftext += String.fromCharCode((c >> 12) | 224);
358
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
359
				utftext += String.fromCharCode((c & 63) | 128);
360
			}
361

    
362
		}
363

    
364
		return utftext;
365
	},
366

    
367
	// private method for UTF-8 decoding
368
	_utf8_decode : function (utftext) {
369
		var string = "";
370
		var i = 0;
371
		var c = c1 = c2 = 0;
372

    
373
		while (i < utftext.length) {
374

    
375
			c = utftext.charCodeAt(i);
376

    
377
			if (c < 128) {
378
				string += String.fromCharCode(c);
379
				i++;
380
			} else if ((c > 191) && (c < 224)) {
381
				c2 = utftext.charCodeAt(i+1);
382
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
383
				i += 2;
384
			} else {
385
				c2 = utftext.charCodeAt(i+1);
386
				c3 = utftext.charCodeAt(i+2);
387
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
388
				i += 3;
389
			}
390

    
391
		}
392

    
393
		return string;
394
	}
395

    
396
};
397

    
398
	<?php if ($_GET['action'] == "load"): ?>
399
		events.push(function() {
400
			$("#fbTarget").val("<?=htmlspecialchars($_GET['path'])?>");
401
			loadFile();
402
		});
403
	<?php endif; ?>
404
//]]>
405
</script>
406

    
407
<?php include("foot.inc");
408

    
409
outputJavaScriptFileInline("filebrowser/browser.js");
(33-33/229)