Project

General

Profile

Download (11.8 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	diag_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=diag_edit.php*
61
##|*MATCH=browser.php*
62
##|*MATCH=vendor/filebrowser/browser.php*
63
##|-PRIV
64

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

    
68
if ($_POST['action']) {
69
	switch ($_POST['action']) {
70
		case 'load':
71
			if (strlen($_POST['file']) < 1) {
72
				print('|5|');
73
				print_info_box(gettext("No file name specified."), 'danger');
74
				print('|');
75
			} elseif (is_dir($_POST['file'])) {
76
				print('|4|');
77
				print_info_box(gettext("Loading a directory is not supported."), 'danger');
78
				print('|');
79
			} elseif (!is_file($_POST['file'])) {
80
				print('|3|');
81
				print_info_box(gettext("File does not exist or is not a regular file."), 'danger');
82
				print('|');
83
			} else {
84
				$data = file_get_contents(urldecode($_POST['file']));
85
				if ($data === false) {
86
					print('|1|');
87
					print_info_box(gettext("Failed to read file."), 'danger');
88
					print('|');
89
				} else {
90
					$data = base64_encode($data);
91
					print("|0|{$_POST['file']}|{$data}|");
92
				}
93
			}
94
			exit;
95

    
96
		case 'save':
97
			if (strlen($_POST['file']) < 1) {
98
				print('|');
99
				print_info_box(gettext("No file name specified."), 'danger');
100
				print('|');
101
			} else {
102
				conf_mount_rw();
103
				$_POST['data'] = str_replace("\r", "", base64_decode($_POST['data']));
104
				$ret = file_put_contents($_POST['file'], $_POST['data']);
105
				conf_mount_ro();
106
				if ($_POST['file'] == "/conf/config.xml" || $_POST['file'] == "/cf/conf/config.xml") {
107
					if (file_exists("/tmp/config.cache")) {
108
						unlink("/tmp/config.cache");
109
					}
110
					disable_security_checks();
111
				}
112
				if ($ret === false) {
113
					print('|');
114
					print_info_box(gettext("Failed to write file."), 'danger');
115
					print('|');
116
				} elseif ($ret != strlen($_POST['data'])) {
117
					print('|');
118
					print_info_box(gettext("Error while writing file."), 'danger');
119
					print('|');
120
				} else {
121
					print('|');
122
					print_info_box(gettext("File saved successfully."), 'success');
123
					print('|');
124
				}
125
			}
126
			exit;
127
	}
128
	exit;
129
}
130

    
131
require("head.inc");
132

    
133
print_callout(gettext("The capabilities offered here can be dangerous. No support is available. Use them at your own risk!"), 'danger', gettext('Advanced Users Only'));
134

    
135
?>
136
<!-- file status box -->
137
<div style="display:none; background:#eeeeee;" id="fileStatusBox">
138
	<div id="fileStatus"></div>
139
</div>
140

    
141
<div class="panel panel-default">
142
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Save / Load a File from the Filesystem")?></h2></div>
143
	<div class="panel-body">
144
		<div class="content">
145
			<form>
146
				<p><input type="text" class="form-control" id="fbTarget"/></p>
147
				<div class="btn-group">
148
					<p>
149
						<button type="button" class="btn btn-default btn-sm" onclick="loadFile();"	value="<?=gettext('Load')?>">
150
							<i class="fa fa-file-text-o"></i>
151
							<?=gettext('Load')?>
152
						</button>
153
						<button type="button" class="btn btn-default btn-sm" id="fbOpen"		value="<?=gettext('Browse')?>">
154
							<i class="fa fa-list"></i>
155
							<?=gettext('Browse')?>
156
						</button>
157
						<button type="button" class="btn btn-default btn-sm" onclick="saveFile();"	value="<?=gettext('Save')?>">
158
							<i class="fa fa-save"></i>
159
							<?=gettext('Save')?>
160
						</button>
161
					</p>
162
				</div>
163
				<p class="pull-right">
164
					<button id="btngoto" class="btn btn-default btn-sm"><i class="fa fa-forward"></i><?=gettext("GoTo Line #")?></button> <input type="number" id="gotoline" size="6" style="padding: 3px 0px;"/>
165
				</p>
166
			</form>
167

    
168
			<div id="fbBrowser" style="display:none; border:1px dashed gray; width:98%; padding:10px"></div>
169

    
170
			<script type="text/javascript">
171
			//<![CDATA[
172
			window.onload=function() {
173
				document.getElementById("fileContent").wrap='off';
174
			}
175
			//]]>
176
			</script>
177
			<textarea id="fileContent" name="fileContent" class="form-control" rows="30" cols="20"></textarea>
178
		</div>
179
	</div>
180
</div>
181

    
182
<script type="text/javascript">
183
//<![CDATA[
184
	events.push(function(){
185

    
186
		function showLine(tarea, lineNum) {
187

    
188
			lineNum--; // array starts at 0
189
			var lines = tarea.value.split("\n");
190

    
191
			// calculate start/end
192
			var startPos = 0, endPos = tarea.value.length;
193
			for(var x = 0; x < lines.length; x++) {
194
				if(x == lineNum) {
195
					break;
196
				}
197
				startPos += (lines[x].length+1);
198

    
199
			}
200

    
201
			var endPos = lines[lineNum].length+startPos;
202

    
203
			// do selection
204
			// Chrome / Firefox
205

    
206
			if(typeof(tarea.selectionStart) != "undefined") {
207
				tarea.focus();
208
				tarea.selectionStart = startPos;
209
				tarea.selectionEnd = endPos;
210
				return true;
211
			}
212

    
213
			// IE
214
			if (document.selection && document.selection.createRange) {
215
				tarea.focus();
216
				tarea.select();
217
				var range = document.selection.createRange();
218
				range.collapse(true);
219
				range.moveEnd("character", endPos);
220
				range.moveStart("character", startPos);
221
				range.select();
222
				return true;
223
			}
224

    
225
			return false;
226
		}
227

    
228
		$("#btngoto").prop('type','button');
229

    
230
		$('#btngoto').click(function() {
231
			var tarea = document.getElementById("fileContent");
232
			showLine(tarea, $('#gotoline').val());
233
		});
234
	});
235

    
236
	function loadFile() {
237
		$("#fileStatus").html("");
238
		$("#fileStatusBox").show(500);
239
		$.ajax(
240
			"<?=$_SERVER['SCRIPT_NAME']?>", {
241
				type: "post",
242
				data: "action=load&file=" + $("#fbTarget").val(),
243
				complete: loadComplete
244
			}
245
		);
246
	}
247

    
248
	function loadComplete(req) {
249
		$("#fileContent").show(1000);
250
		var values = req.responseText.split("|");
251
		values.shift(); values.pop();
252

    
253
		if (values.shift() == "0") {
254
			var file = values.shift();
255
			var fileContent = window.atob(values.join("|"));
256

    
257
			$("#fileContent").val(fileContent);
258
		} else {
259
			$("#fileStatus").html(values[0]);
260
			$("#fileContent").val("");
261
		}
262

    
263
		$("#fileContent").show(1000);
264
	}
265

    
266
	function saveFile(file) {
267
		$("#fileStatus").html("");
268
		$("#fileStatusBox").show(500);
269

    
270
		var fileContent = Base64.encode($("#fileContent").val());
271
		fileContent = fileContent.replace(/\+/g, "%2B");
272

    
273
		$.ajax(
274
			"<?=$_SERVER['SCRIPT_NAME']?>", {
275
				type: "post",
276
				data: "action=save&file=" + $("#fbTarget").val() +
277
							"&data=" + fileContent,
278
				complete: function(req) {
279
					var values = req.responseText.split("|");
280
					$("#fileStatus").html(values[1]);
281
				}
282
			}
283
		);
284
	}
285

    
286
/**
287
 *
288
 *	Base64 encode / decode
289
 *	http://www.webtoolkit.info/
290
 *	http://www.webtoolkit.info/licence
291
 **/
292

    
293
var Base64 = {
294

    
295
	// private property
296
	_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
297

    
298
	// public method for encoding
299
	encode : function (input) {
300
		var output = "";
301
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
302
		var i = 0;
303

    
304
		input = Base64._utf8_encode(input);
305

    
306
		while (i < input.length) {
307

    
308
			chr1 = input.charCodeAt(i++);
309
			chr2 = input.charCodeAt(i++);
310
			chr3 = input.charCodeAt(i++);
311

    
312
			enc1 = chr1 >> 2;
313
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
314
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
315
			enc4 = chr3 & 63;
316

    
317
			if (isNaN(chr2)) {
318
				enc3 = enc4 = 64;
319
			} else if (isNaN(chr3)) {
320
				enc4 = 64;
321
			}
322

    
323
			output = output +
324
			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
325
			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
326

    
327
		}
328

    
329
		return output;
330
	},
331

    
332
	// public method for decoding
333
	decode : function (input) {
334
		var output = "";
335
		var chr1, chr2, chr3;
336
		var enc1, enc2, enc3, enc4;
337
		var i = 0;
338

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

    
341
		while (i < input.length) {
342

    
343
			enc1 = this._keyStr.indexOf(input.charAt(i++));
344
			enc2 = this._keyStr.indexOf(input.charAt(i++));
345
			enc3 = this._keyStr.indexOf(input.charAt(i++));
346
			enc4 = this._keyStr.indexOf(input.charAt(i++));
347

    
348
			chr1 = (enc1 << 2) | (enc2 >> 4);
349
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
350
			chr3 = ((enc3 & 3) << 6) | enc4;
351

    
352
			output = output + String.fromCharCode(chr1);
353

    
354
			if (enc3 != 64) {
355
				output = output + String.fromCharCode(chr2);
356
			}
357
			if (enc4 != 64) {
358
				output = output + String.fromCharCode(chr3);
359
			}
360

    
361
		}
362

    
363
		output = Base64._utf8_decode(output);
364

    
365
		return output;
366

    
367
	},
368

    
369
	// private method for UTF-8 encoding
370
	_utf8_encode : function (string) {
371
		string = string.replace(/\r\n/g,"\n");
372
		var utftext = "";
373

    
374
		for (var n = 0; n < string.length; n++) {
375

    
376
			var c = string.charCodeAt(n);
377

    
378
			if (c < 128) {
379
				utftext += String.fromCharCode(c);
380
			} else if ((c > 127) && (c < 2048)) {
381
				utftext += String.fromCharCode((c >> 6) | 192);
382
				utftext += String.fromCharCode((c & 63) | 128);
383
			} else {
384
				utftext += String.fromCharCode((c >> 12) | 224);
385
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
386
				utftext += String.fromCharCode((c & 63) | 128);
387
			}
388

    
389
		}
390

    
391
		return utftext;
392
	},
393

    
394
	// private method for UTF-8 decoding
395
	_utf8_decode : function (utftext) {
396
		var string = "";
397
		var i = 0;
398
		var c = c1 = c2 = 0;
399

    
400
		while (i < utftext.length) {
401

    
402
			c = utftext.charCodeAt(i);
403

    
404
			if (c < 128) {
405
				string += String.fromCharCode(c);
406
				i++;
407
			} else if ((c > 191) && (c < 224)) {
408
				c2 = utftext.charCodeAt(i+1);
409
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
410
				i += 2;
411
			} else {
412
				c2 = utftext.charCodeAt(i+1);
413
				c3 = utftext.charCodeAt(i+2);
414
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
415
				i += 3;
416
			}
417

    
418
		}
419

    
420
		return string;
421
	}
422

    
423
};
424

    
425
	<?php if ($_GET['action'] == "load"): ?>
426
		events.push(function() {
427
			$("#fbTarget").val("<?=htmlspecialchars($_GET['path'])?>");
428
			loadFile();
429
		});
430
	<?php endif; ?>
431
//]]>
432
</script>
433

    
434
<?php include("foot.inc");
435

    
436
outputJavaScriptFileInline("vendor/filebrowser/browser.js");
(14-14/225)