Project

General

Profile

Download (10.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * diag_edit.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2021 Rubicon Communications, LLC (Netgate)
9
 * All rights reserved.
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 * http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23

    
24
##|+PRIV
25
##|*IDENT=page-diagnostics-edit
26
##|*NAME=Diagnostics: Edit File
27
##|*DESCR=Allow access to the 'Diagnostics: Edit File' page.
28
##|*WARN=standard-warning-root
29
##|*MATCH=diag_edit.php*
30
##|*MATCH=browser.php*
31
##|*MATCH=vendor/filebrowser/browser.php*
32
##|-PRIV
33

    
34
$pgtitle = array(gettext("Diagnostics"), gettext("Edit File"));
35
require_once("guiconfig.inc");
36

    
37
if ($_POST['action']) {
38
	switch ($_POST['action']) {
39
		case 'load':
40
			if (strlen($_POST['file']) < 1) {
41
				print('|5|');
42
				print_info_box(gettext("No file name specified."), 'danger');
43
				print('|');
44
			} elseif (is_dir($_POST['file'])) {
45
				print('|4|');
46
				print_info_box(gettext("Loading a directory is not supported."), 'danger');
47
				print('|');
48
			} elseif (!is_file($_POST['file'])) {
49
				print('|3|');
50
				print_info_box(gettext("File does not exist or is not a regular file."), 'danger');
51
				print('|');
52
			} else {
53
				$data = file_get_contents(urldecode($_POST['file']));
54
				if ($data === false) {
55
					print('|1|');
56
					print_info_box(gettext("Failed to read file."), 'danger');
57
					print('|');
58
				} else {
59
					$data = base64_encode($data);
60
					print("|0|{$_POST['file']}|{$data}|");
61
				}
62
			}
63
			exit;
64

    
65
		case 'save':
66
			if (strlen($_POST['file']) < 1) {
67
				print('|');
68
				print_info_box(gettext("No file name specified."), 'danger');
69
				print('|');
70
			} else {
71
				$_POST['data'] = str_replace("\r", "", base64_decode($_POST['data']));
72
				$ret = file_put_contents($_POST['file'], $_POST['data']);
73
				if ($_POST['file'] == "/conf/config.xml" || $_POST['file'] == "/cf/conf/config.xml") {
74
					if (file_exists("/tmp/config.cache")) {
75
						unlink("/tmp/config.cache");
76
					}
77
					disable_security_checks();
78
				}
79
				if ($ret === false) {
80
					print('|');
81
					print_info_box(gettext("Failed to write file."), 'danger');
82
					print('|');
83
				} elseif ($ret != strlen($_POST['data'])) {
84
					print('|');
85
					print_info_box(gettext("Error while writing file."), 'danger');
86
					print('|');
87
				} else {
88
					print('|');
89
					print_info_box(gettext("File saved successfully."), 'success');
90
					print('|');
91
				}
92
			}
93
			exit;
94
	}
95
	exit;
96
}
97

    
98
require_once("head.inc");
99

    
100
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'));
101

    
102
?>
103
<!-- file status box -->
104
<div style="display:none; background:#eeeeee;" id="fileStatusBox">
105
	<div id="fileStatus"></div>
106
</div>
107

    
108
<div class="panel panel-default">
109
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Save / Load a File from the Filesystem")?></h2></div>
110
	<div class="panel-body">
111
		<div class="content">
112
			<form>
113
				<p><input type="text" class="form-control" id="fbTarget" placeholder="<?=gettext('Path to file to be edited')?>"/></p>
114
				<div class="btn-group">
115
					<p>
116
						<button type="button" class="btn btn-default btn-sm" onclick="loadFile();"	value="<?=gettext('Load')?>">
117
							<i class="fa fa-file-text-o"></i>
118
							<?=gettext('Load')?>
119
						</button>
120
						<button type="button" class="btn btn-default btn-sm" id="fbOpen"		value="<?=gettext('Browse')?>">
121
							<i class="fa fa-list"></i>
122
							<?=gettext('Browse')?>
123
						</button>
124
						<button type="button" class="btn btn-default btn-sm" onclick="saveFile();"	value="<?=gettext('Save')?>">
125
							<i class="fa fa-save"></i>
126
							<?=gettext('Save')?>
127
						</button>
128
					</p>
129
				</div>
130
				<p class="pull-right">
131
					<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;"/>
132
				</p>
133
			</form>
134

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

    
137
			<script type="text/javascript">
138
			//<![CDATA[
139
			window.onload=function() {
140
				document.getElementById("fileContent").wrap='off';
141
			}
142
			//]]>
143
			</script>
144
			<textarea id="fileContent" name="fileContent" class="form-control" rows="30" cols="20"></textarea>
145
		</div>
146
	</div>
147
</div>
148

    
149
<script type="text/javascript">
150
//<![CDATA[
151
	events.push(function(){
152
		// Hitting the enter key will do the same as clicking the 'Load' button
153
		$("#fbTarget").on("keyup", function (event) {
154
			if (event.keyCode == 13) {
155
				loadFile();
156
			}
157
		});
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
		//On clicking the GoTo button, validate the entered value
204
		// and highlight the required line
205
		$('#btngoto').click(function() {
206
			var tarea = document.getElementById("fileContent");
207
			var gtl = $('#gotoline').val();
208
			var lines = $("#fileContent").val().split(/\r|\r\n|\n/).length;
209

    
210
			if (gtl < 1) {
211
				gtl = 1;
212
			}
213

    
214
			if (gtl > lines) {
215
				gtl = lines;
216
			}
217

    
218
			showLine(tarea, gtl);
219
		});
220

    
221
		// Goto the specified line on pressing the Enter key within the "Goto line" input element
222
		$('#gotoline').keyup(function(e) {
223
			if(e.keyCode == 13) {
224
				$('#btngoto').click();
225
			}
226
		});
227

    
228
	}); // e-o-events.push()
229

    
230
	function loadFile() {
231
		$("#fileStatus").html("");
232
		$("#fileStatusBox").show(500);
233
		$.ajax(
234
			"<?=$_SERVER['SCRIPT_NAME']?>", {
235
				type: "post",
236
				data: "action=load&file=" + $("#fbTarget").val(),
237
				complete: loadComplete
238
			}
239
		);
240
	}
241

    
242
	function loadComplete(req) {
243
		$("#fileContent").show(1000);
244
		var values = req.responseText.split("|");
245
		values.shift(); values.pop();
246

    
247
		if (values.shift() == "0") {
248
			var file = values.shift();
249
			var fileContent = window.Base64.decode(values.join("|"));
250

    
251
			$("#fileContent").val(fileContent);
252
		} else {
253
			$("#fileStatus").html(values[0]);
254
			$("#fileContent").val("");
255
		}
256

    
257
		$("#fileContent").show(1000);
258
	}
259

    
260
	function saveFile(file) {
261
		$("#fileStatus").html("");
262
		$("#fileStatusBox").show(500);
263

    
264
		var fileContent = Base64.encode($("#fileContent").val());
265
		fileContent = fileContent.replace(/\+/g, "%2B");
266

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

    
280
/**
281
 *
282
 *	Base64 encode / decode
283
 *	http://www.webtoolkit.info/
284
 *	http://www.webtoolkit.info/licence
285
 **/
286

    
287
var Base64 = {
288

    
289
	// private property
290
	_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
291

    
292
	// public method for encoding
293
	encode : function (input) {
294
		var output = "";
295
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
296
		var i = 0;
297

    
298
		input = Base64._utf8_encode(input);
299

    
300
		while (i < input.length) {
301

    
302
			chr1 = input.charCodeAt(i++);
303
			chr2 = input.charCodeAt(i++);
304
			chr3 = input.charCodeAt(i++);
305

    
306
			enc1 = chr1 >> 2;
307
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
308
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
309
			enc4 = chr3 & 63;
310

    
311
			if (isNaN(chr2)) {
312
				enc3 = enc4 = 64;
313
			} else if (isNaN(chr3)) {
314
				enc4 = 64;
315
			}
316

    
317
			output = output +
318
			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
319
			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
320

    
321
		}
322

    
323
		return output;
324
	},
325

    
326
	// public method for decoding
327
	decode : function (input) {
328
		var output = "";
329
		var chr1, chr2, chr3;
330
		var enc1, enc2, enc3, enc4;
331
		var i = 0;
332

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

    
335
		while (i < input.length) {
336

    
337
			enc1 = this._keyStr.indexOf(input.charAt(i++));
338
			enc2 = this._keyStr.indexOf(input.charAt(i++));
339
			enc3 = this._keyStr.indexOf(input.charAt(i++));
340
			enc4 = this._keyStr.indexOf(input.charAt(i++));
341

    
342
			chr1 = (enc1 << 2) | (enc2 >> 4);
343
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
344
			chr3 = ((enc3 & 3) << 6) | enc4;
345

    
346
			output = output + String.fromCharCode(chr1);
347

    
348
			if (enc3 != 64) {
349
				output = output + String.fromCharCode(chr2);
350
			}
351
			if (enc4 != 64) {
352
				output = output + String.fromCharCode(chr3);
353
			}
354

    
355
		}
356

    
357
		output = Base64._utf8_decode(output);
358

    
359
		return output;
360

    
361
	},
362

    
363
	// private method for UTF-8 encoding
364
	_utf8_encode : function (string) {
365
		string = string.replace(/\r\n/g,"\n");
366
		var utftext = "";
367

    
368
		for (var n = 0; n < string.length; n++) {
369

    
370
			var c = string.charCodeAt(n);
371

    
372
			if (c < 128) {
373
				utftext += String.fromCharCode(c);
374
			} else if ((c > 127) && (c < 2048)) {
375
				utftext += String.fromCharCode((c >> 6) | 192);
376
				utftext += String.fromCharCode((c & 63) | 128);
377
			} else {
378
				utftext += String.fromCharCode((c >> 12) | 224);
379
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
380
				utftext += String.fromCharCode((c & 63) | 128);
381
			}
382

    
383
		}
384

    
385
		return utftext;
386
	},
387

    
388
	// private method for UTF-8 decoding
389
	_utf8_decode : function (utftext) {
390
		var string = "";
391
		var i = 0;
392
		var c = c1 = c2 = 0;
393

    
394
		while (i < utftext.length) {
395

    
396
			c = utftext.charCodeAt(i);
397

    
398
			if (c < 128) {
399
				string += String.fromCharCode(c);
400
				i++;
401
			} else if ((c > 191) && (c < 224)) {
402
				c2 = utftext.charCodeAt(i+1);
403
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
404
				i += 2;
405
			} else {
406
				c2 = utftext.charCodeAt(i+1);
407
				c3 = utftext.charCodeAt(i+2);
408
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
409
				i += 3;
410
			}
411

    
412
		}
413

    
414
		return string;
415
	}
416

    
417
};
418

    
419
	<?php if ($_POST['action'] == "load"): ?>
420
		events.push(function() {
421
			$("#fbTarget").val("<?=htmlspecialchars($_POST['path'])?>");
422
			loadFile();
423
		});
424
	<?php endif; ?>
425

    
426
//]]>
427
</script>
428

    
429
<?php include("foot.inc");
430

    
431
outputJavaScriptFileInline("vendor/filebrowser/browser.js");
(16-16/229)