# HG changeset patch # User Aleksej Bobylev # Date 1429880414 -10800 # Node ID 7ca14d55e7054141595c251c1e8c8fe04ff4ea9d # Parent d0dbe11a20606858c088da4981bb838995043068 Add prism.js syntax highlighter; now files can be edited "in place" without page reloading; allow ANY characters in the Wi-Fi password (bug 126); change web-app layout: main window isn't scrollable, with scrollable contents. diff -r d0dbe11a2060 -r 7ca14d55e705 README.devel --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.devel Fri Apr 24 16:00:14 2015 +0300 @@ -0,0 +1,159 @@ +Various Development Notes +========================= + +-------------------------------------------------------------------------------- + +network.cgi +----------- + +Goal: allow ANY symbols in the WPA PSK (Wi-Fi password). +We can find WPA PSK in the different places, and there are different +restrictions to write it. + +a) /etc/network.conf: SliTaz system wide networking configuration; +b) /etc/wpa/wpa.conf: wpa_supplicant configuration file; +c) html input form in the TazPanel > Network > Wireless; +d) saved passwords for known networks in the javascript in the same place. + +Let's see all that files/places one by one. + + +a) network.conf + +Really "network.conf" is a shell script. It contains variables definitions, and +it sourced into other shell scripts to define all Wi-Fi configuration variables. +By default, we can see variable and its content in the double quotes: + +WIFI_KEY="mypassword" + +There are many pitfalls if we allow ANY symbols here: + +Variable expansion: +WIFI_KEY="123$HOME" +WIFI_KEY="$0$#$? *" + +Command expansion: +WIFI_KEY="123$(echo 456)789" +WIFI_KEY="`rm -rf /`" + +Quoting problem: +WIFI_KEY="abc"def'ghi" + +Seems, we'll solve the problem when escape some symbols: +\ → \\ +" → \" +$ → \$ +` → \` + +Another solution exists (and currently I stick to it): single quotes. We need no +escape anything but single quotes (') in the single quotes terminated string. +And yes, this quoting is a pain for brain: + +Password: abc"def'ghi +String : WIFI_KEY='abc"def'"'"'ghi' +But it is simple work for sed command. + + +b) wpa.conf + +wpa_supplicant actually connects us to our Wi-Fi networks, and it is a file +where we can store all our networks settings, including passwords. It is handy +when you have one network at home, other - at work, and another - at your +friends home. Really, you shouldn't to re-enter all these passwords again. + +We can read a lot of useful information in the wpa_cupplicant.conf file +(/etc/wpa/wpa_supplicant.conf): + +# psk: WPA preshared key; 256-bit pre-shared key +# The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e., +# 32 bytes or as an ASCII passphrase (in which case, the real PSK will be +# generated using the passphrase and SSID). ASCII passphrase must be between +# 8 and 63 characters (inclusive). ext: format can +# be used to indicate that the PSK/passphrase is stored in external storage. +# This field is not needed, if WPA-EAP is used. +# Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys +# from ASCII passphrase. This process uses lot of CPU and wpa_supplicant +# startup and reconfiguration time can be optimized by generating the PSK only +# only when the passphrase or SSID has actually changed. + + +Interesting and good method to use 64 symbols "passwords", maybe we switch to it +sometimes. Example of using "wpa_passphrase": +Let network name is: my_wifi +Let password is : abc'def"ghi +Let's run utility twice - with different quoting style: + +tux@slitaz:~$ wpa_passphrase my_wifi "abc'def\"ghi" +network={ + ssid="my_wifi" + #psk="abc'def"ghi" + psk=e99c121a998a0c35419b16fd56beb38d2b471fd5519518c056af933e9daf3e30 +} +tux@slitaz:~$ wpa_passphrase my_wifi 'abc'"'"'def"ghi' +network={ + ssid="my_wifi" + #psk="abc'def"ghi" + psk=e99c121a998a0c35419b16fd56beb38d2b471fd5519518c056af933e9daf3e30 +} + +Here psk are identical, so we can use this method. + +But I can't find advanced info about quoting style in the wpa_supplicant +configuration file. So, I ended with little experiment. I've created new +network connection in my Android smartphone and viewed my +/data/misc/wifi/wpa_supplicant.conf file using Root Explorer application: + +network={ + ssid="my_wifi" + scan_ssid=1 + psk="abc'def"ghi" + key_mgmt=WPA-PSK +} + +Yes, we can see unpaired quotes. Really don't know is it right. Maybe, +wpa_supplicant just readed line content between first and last quotes. Need to +dig into sources... And now I not quote psk in any manner. + + +c) network.cgi form input + +Piece of html code: + + + +Here we free to use single quotes or double quotes, but we should escape them +in the html manner: +' → ' +" → " + +Also, don't forget about these symbols: +& → & +< → < +> → > + + +d) network.cgi javascript database + +Also, we store passwords in the known networks database in the form of +javascript to gain user experience without page to be reloaded: you can click +Wi-Fi network name and script will fill its password for you. + +Here example of that script on the html page: + + + +Here we need to escape ('"&<>) symbols as described above. + + +So, what do you think about this very special password? :=D +a'b"c $(echo 2)=$HOME`date`\t&#x + +-------------------------------------------------------------------------------- diff -r d0dbe11a2060 -r 7ca14d55e705 index.cgi --- a/index.cgi Sat Apr 18 16:26:58 2015 +0300 +++ b/index.cgi Fri Apr 24 16:00:14 2015 +0300 @@ -112,6 +112,7 @@ header file="$(GET file)" action="$(POST action)"; [ -z "$action" ] && action="$(GET action)" # receive 'action' both on POST or GET + title="$(POST title)"; [ -z "$title" ] && title="$(GET title)" # (optional) case $file in *.html) @@ -125,8 +126,8 @@ cat <
- $file -
+ ${title:-$file} +
@@ -173,17 +174,22 @@ fi cat < +
- $file + ${title:-$file} EOT if [ -w "$file" ]; then cat < + + + + + $(file_is_modified $file button) - + EOT elif [ -r "$file" ]; then cat <
-
+		
 EOT
+			end_code=''
 			# Handle file type by extension as a Web Server does it.
 			case "$file" in
+				*.sh|*.cgi|*/receipt|*.conf)
+					echo ''; end_code=''
+					cat | htmlize ;;
+				*.ini)
+					echo ''; end_code=''
+					cat | htmlize ;;
 				*.conf|*.lst)
 					syntax_highlighter conf ;;
-				*.sh|*.cgi)
-					syntax_highlighter sh ;;
 				*Xorg.0.log)
 					syntax_highlighter xlog ;;
 				*dmesg.log)
 					syntax_highlighter kernel ;;
-				*/receipt)
-					syntax_highlighter sh ;;
 				*)
 					cat | htmlize ;;
 			esac < $file
 			cat <
+$end_code
EOT @@ -295,7 +304,7 @@ case "$cmd" in usage|help) _ 'Small non-interactive terminal emulator.'; echo - _ 'Run any command at your own risk, avoid interactive commands (%s)' "nano, mc, ..."; echo + _ 'Run any command at your own risk, avoid interactive commands (%s)' 'nano, mc, ...'; echo ;; wget*) dl=/var/cache/downloads @@ -398,7 +407,7 @@ fi cat < +
$(_ 'Terminal settings')
diff -r d0dbe11a2060 -r 7ca14d55e705 lib/libtazpanel --- a/lib/libtazpanel Sat Apr 18 16:26:58 2015 +0300 +++ b/lib/libtazpanel Fri Apr 24 16:00:14 2015 +0300 @@ -7,6 +7,16 @@ . /lib/libtaz.sh + +# Redefine gettext functions + +_() { local T="$1"; shift; printf "$(gettext "$T")" "$@"; echo; } +_n() { local T="$1"; shift; printf "$(gettext "$T")" "$@"; } +_p() { + local S="$1" P="$2" N="$3"; shift 3; + printf "$(ngettext "$S" "$P" "$N")" "$@"; } + + [ "$(id -un)" == "${REMOTE_USER:=nobody}" ] || exec su -s /bin/sh -c "$(realpath $0) $@" $REMOTE_USER diff -r d0dbe11a2060 -r 7ca14d55e705 lib/prism.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/prism.js Fri Apr 24 16:00:14 2015 +0300 @@ -0,0 +1,5 @@ +/* http://prismjs.com/download.html?themes=prism&languages=clike+bash+ini */ +self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{};var Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content),e.alias):"Array"===t.util.type(e)?e.map(t.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(d instanceof a)){u.lastIndex=0;var m=u.exec(d);if(m){c&&(f=m[1].length);var y=m.index-1+f,m=m[0].slice(f),v=m.length,k=y+v,b=d.slice(0,y+1),w=d.slice(k+1),N=[p,1];b&&N.push(b);var O=new a(l,g?t.tokenize(m,g):m,h);N.push(O),w&&N.push(w),Array.prototype.splice.apply(r,N)}}}}}return r},hooks:{all:{},add:function(e,n){var a=t.hooks.all;a[e]=a[e]||[],a[e].push(n)},run:function(e,n){var a=t.hooks.all[e];if(a&&a.length)for(var r,i=0;r=a[i++];)r(n)}}},n=t.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(n.stringify=function(e,a,r){if("string"==typeof e)return e;if("Array"===t.util.type(e))return e.map(function(t){return n.stringify(t,a,e)}).join("");var i={type:e.type,content:n.stringify(e.content,a,r),tag:"span",classes:["token",e.type],attributes:{},language:a,parent:r};if("comment"==i.type&&(i.attributes.spellcheck="true"),e.alias){var l="Array"===t.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(i.classes,l)}t.hooks.run("wrap",i);var s="";for(var o in i.attributes)s+=o+'="'+(i.attributes[o]||"")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'" '+s+">"+i.content+""},!self.document)return self.addEventListener?(self.addEventListener("message",function(e){var n=JSON.parse(e.data),a=n.language,r=n.code;self.postMessage(JSON.stringify(t.util.encode(t.tokenize(r,t.languages[a])))),self.close()},!1),self.Prism):self.Prism;var a=document.getElementsByTagName("script");return a=a[a.length-1],a&&(t.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism);; +Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:/("|')(\\\n|\\?.)*?\1/,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":{pattern:/[a-z0-9_]+\(/i,inside:{punctuation:/\(/}},number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/,ignore:/&(lt|gt|amp);/i,punctuation:/[{}[\];(),.:]/};; +Prism.languages.bash=Prism.languages.extend("clike",{comment:{pattern:/(^|[^"{\\])(#.*?(\r?\n|$))/,lookbehind:!0},string:{pattern:/("|')(\\?[\s\S])*?\1/,inside:{property:/\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^\}]+\})/}},number:{pattern:/([^\w\.])-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,lookbehind:!0},"function":/\b(?:alias|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|cut|date|dc|dd|ddrescue|declare|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|echo|egrep|eject|enable|env|ethtool|eval|exec|exit|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|select|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|until|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)\b/,keyword:/\b(if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)\b/}),Prism.languages.insertBefore("bash","keyword",{property:/\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^}]+\})/}),Prism.languages.insertBefore("bash","comment",{important:/(^#!\s*\/bin\/bash)|(^#!\s*\/bin\/sh)/});; +Prism.languages.ini={comment:/^\s*;.*$/m,important:/\[.*?\]/m,constant:/^\s*[^\s=]+?(?=[ \t]*=)/m,"attr-value":{pattern:/=.*/m,inside:{punctuation:/^[=]/}}};; diff -r d0dbe11a2060 -r 7ca14d55e705 lib/tazpanel.js --- a/lib/tazpanel.js Sat Apr 18 16:26:58 2015 +0300 +++ b/lib/tazpanel.js Fri Apr 24 16:00:14 2015 +0300 @@ -468,3 +468,49 @@ else improveText.value = document.getElementById(improveType.value).innerText; } + + +// +// Edit and save files "in place" +// + +function editFile() { + document.getElementById('edit_button').style.display = 'none'; + document.getElementById('save_button').style.display = ''; + + with(document.getElementById('fileContent')) { + contentEditable = true; + onkeydown = insertTab; + focus(); + } +} + +function saveFile(file, fileTitle) { + var newArea = document.createElement('TEXTAREA'); + with(newArea) { + name = 'content'; + textContent = document.getElementById('fileContent').textContent; + } + + var newTitle = document.createElement('INPUT'); + with(newTitle) { + name = 'title'; + value = fileTitle; + } + + var newForm = document.createElement('FORM'); + with(newForm) { + appendChild(newArea); + appendChild(newTitle); + method = 'post'; + action = "?file=" + file; + submit(); + } +} + +function insertTab(e) { + var evt = e ? e:event; + if (evt.keyCode == 9) { + evt.preventDefault(); + } +} diff -r d0dbe11a2060 -r 7ca14d55e705 network.cgi --- a/network.cgi Sat Apr 18 16:26:58 2015 +0300 +++ b/network.cgi Fri Apr 24 16:00:14 2015 +0300 @@ -25,34 +25,15 @@ ifconfig $WIFI_INTERFACE up iwconfig $WIFI_INTERFACE txpower auto /etc/init.d/network.sh restart | log - # Sleep until connection established (max 20 seconds) - for i in $(seq 20); do + + # Sleep until connection established (max 5 seconds) + for i in $(seq 5); do [ -n "$(iwconfig 2>/dev/null | fgrep Link)" ] && break sleep 1 done } -# Connect to a Wi-Fi network -connect_wifi() { - /etc/init.d/network.sh stop | log - sed -i \ - -e "s|^WIFI_ESSID=.*|WIFI_ESSID=\"$(GET essid)\"|" \ - -e "s|^WIFI_BSSID=.*|WIFI_BSSID=\"$(GET bssid)\"|" \ - -e "s|^WIFI_KEY_TYPE=.*|WIFI_KEY_TYPE=\"$(GET keyType)\"|" \ - -e "s|^WIFI_KEY=.*|WIFI_KEY=\"$(GET password)\"|" \ - -e "s|^WIFI_EAP_METHOD=.*|WIFI_EAP_METHOD=\"$(GET eap)\"|" \ - -e "s|^WIFI_CA_CERT=.*|WIFI_CA_CERT=\"$(GET caCert)\"|" \ - -e "s|^WIFI_CLIENT_CERT=.*|WIFI_CLIENT_CERT=\"$(GET clientCert)\"|" \ - -e "s|^WIFI_IDENTITY=.*|WIFI_IDENTITY=\"$(GET identity)\"|" \ - -e "s|^WIFI_ANONYMOUS_IDENTITY=.*|WIFI_ANONYMOUS_IDENTITY=\"$(GET anonymousIdentity)\"|" \ - -e "s|^WIFI_PHASE2=.*|WIFI_PHASE2=\"$(GET phase2)\"|" \ - /etc/network.conf - . /etc/network.conf - start_wifi -} - - # Start an Ethernet connection start_eth() { @@ -95,11 +76,24 @@ if ($0 ~ "=") { if (begin_obj == 0) printf ", "; begin_obj = 0; - split($0, a, "="); - if (a[2] ~ "\"") - printf "%s:%s", a[1], a[2]; - else - printf "%s:\"%s\"", a[1], a[2]; + + # split line into variable and value (note "=" can appear in the value) + split($0, a, "="); variable = a[1]; + value = gensub(variable "=", "", ""); + + # escape html entities + value = gensub("\\\\", "\\\\", "g", value); + value = gensub("&", "\\&", "g", value); + value = gensub("<", "\\<", "g", value); + value = gensub(">", "\\>", "g", value); + value = gensub("\"", "\\\"", "g", value); + + # if value was already quoted - remove \" from begin and end + if (substr(value, 1, 2) == "\\\"") + value = substr(value, 3, length(value) - 4); + + # output in form: variable:"escaped value" + printf "%s:\"%s\"", variable, value; } } if (network == 1 && $0 ~ "}") { printf "}"; network = 0; next; } @@ -112,11 +106,12 @@ # Waiting for network link up wait_up() { - for i in $(seq 10); do + for i in $(seq 5); do [ -z "$(cat /sys/class/net/*/operstate | fgrep up)"] && sleep 1 done } + # Actions commands before page is displayed case " $(GET) " in @@ -134,14 +129,38 @@ start_wifi ;; *\ start_eth\ *) start_eth ;; - *\ connect_wifi\ *) - connect_wifi ;; *\ host\ *) get_hostname="$(GET host)" echo $(_ 'Changed hostname: %s' $get_hostname) | log echo "$get_hostname" > /etc/hostname ;; esac +case " $(POST) " in + *\ connect_wifi\ *) + # Connect to a Wi-Fi network + /etc/init.d/network.sh stop | log + password="$(POST password)" + + # Escape special characters to use with sed substitutions + password="$(echo -n "$password" | sed 's|\\|\\\\|g; s|&|\\\&|g' | sed "s|'|'\"'\"'|g")" + + sed -i \ + -e "s|^WIFI_ESSID=.*|WIFI_ESSID=\"$(POST essid)\"|" \ + -e "s|^WIFI_BSSID=.*|WIFI_BSSID=\"$(POST bssid)\"|" \ + -e "s|^WIFI_KEY_TYPE=.*|WIFI_KEY_TYPE=\"$(POST keyType)\"|" \ + -e "s|^WIFI_KEY=.*|WIFI_KEY='$password'|" \ + -e "s|^WIFI_EAP_METHOD=.*|WIFI_EAP_METHOD=\"$(POST eap)\"|" \ + -e "s|^WIFI_CA_CERT=.*|WIFI_CA_CERT=\"$(POST caCert)\"|" \ + -e "s|^WIFI_CLIENT_CERT=.*|WIFI_CLIENT_CERT=\"$(POST clientCert)\"|" \ + -e "s|^WIFI_IDENTITY=.*|WIFI_IDENTITY=\"$(POST identity)\"|" \ + -e "s|^WIFI_ANONYMOUS_IDENTITY=.*|WIFI_ANONYMOUS_IDENTITY=\"$(POST anonymousIdentity)\"|" \ + -e "s|^WIFI_PHASE2=.*|WIFI_PHASE2=\"$(POST phase2)\"|" \ + /etc/network.conf + . /etc/network.conf + start_wifi + ;; +esac + # Get values only now since they could have been modified by actions. @@ -412,18 +431,14 @@ EOT - # ESSID names are clickable - #SELECT="$(GET select)" - #if [ -n "$SELECT" ]; then - # [ "$SELECT" != "$WIFI_ESSID" ] && WIFI_KEY='' - # WIFI_ESSID="$SELECT" - #fi + # Escape html characters in the WIFI_KEY + WIFI_KEY_ESCAPED="$(echo -n "$WIFI_KEY" | sed 's|&|\&|g; s|<|\<|g; s|>|\>|g; s|"|\"|g')" cat <
$(_ 'Connection')
- + @@ -487,7 +502,7 @@ - - -
$(_ 'Password')
- +