diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d079b2352ceb9dc8558e2645be8933e5a2c9abab..a41e1dbcf67bbf9df529e58c2beaa05dbae4fa2e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -10,7 +10,7 @@ jobs: steps: - uses: actions/checkout@v1 - name: Install Dependencies - run: sudo apt install lua-check + run: sudo apt-get -y update && sudo apt-get -y install lua-check - name: Install example site run: ln -s ./docs/site-example ./site - name: Lint Lua code @@ -22,7 +22,7 @@ jobs: steps: - uses: actions/checkout@v1 - name: Install Dependencies - run: sudo apt install shellcheck + run: sudo apt-get -y update && sudo apt-get -y install shellcheck - name: Install example site run: ln -s ./docs/site-example ./site - name: Lint shell code diff --git a/Makefile b/Makefile index 4ff9f0c6007de2e531133ce1c4aebf733a8f41d2..68179393b4f1c7e741f169387c389c1fd4a1ac8c 100644 --- a/Makefile +++ b/Makefile @@ -19,8 +19,9 @@ escape = '$(subst ','\'',$(1))' GLUON_SITEDIR ?= site $(eval $(call mkabspath,GLUON_SITEDIR)) -$(GLUON_SITEDIR)/site.mk: - $(error No site configuration was found. Please check out a site configuration to $(GLUON_SITEDIR)) +ifeq ($(realpath $(GLUON_SITEDIR)/site.mk),) +$(error No site configuration was found. Please check out a site configuration to $(GLUON_SITEDIR)) +endif include $(GLUON_SITEDIR)/site.mk @@ -176,6 +177,10 @@ config: $(LUA) FORCE $(GLUON_ENV) $(LUA) scripts/target_config_check.lua +container: FORCE + @scripts/container.sh + + all: config +@ $(GLUON_ENV) $(LUA) scripts/clean_output.lua diff --git a/contrib/Dockerfile b/contrib/docker/Dockerfile similarity index 100% rename from contrib/Dockerfile rename to contrib/docker/Dockerfile diff --git a/docs/user/getting_started.rst b/docs/user/getting_started.rst index 4d2067323f5fd06641fdafda10ac0d588a4e2794..7fb7b37efe038c49fd7b923d72e71b743289e036 100644 --- a/docs/user/getting_started.rst +++ b/docs/user/getting_started.rst @@ -40,6 +40,12 @@ freshly installed Debian Stretch system the following packages are required: * `time` (built-in `time` doesn't work) +We also provide a container environment that already tracks all these dependencies. It quickly gets you up and running, if you already have either Docker or Podman installed locally. + +:: + + ./scripts/container.sh + Building the images ------------------- diff --git a/docs/user/site.rst b/docs/user/site.rst index 408cf4553c5190bd6ffe21c09dec8ddf60977391..31fb2653597a7cb7f9696c569737f9925138469a 100644 --- a/docs/user/site.rst +++ b/docs/user/site.rst @@ -478,7 +478,7 @@ config_mode \: optional *openlayers_url* allows to override the base URL of the *build/ol.js* and *css/ol.css* files (the default is - ``https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.2.0``). + ``https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@35ffe7626ce16c372143f3c903950750075e7068/en/v5.3.0``). It is also possible to replace the default tile layer (which is OpenStreetMap) with a custom one using the *tile_layer* section. Only XYZ layers are supported at this point. diff --git a/modules b/modules index 21929b6e61b8ba616dc1422b59b93778b895f1bd..c94649ce84e207da77d4c164d4faf82d06b2ce54 100644 --- a/modules +++ b/modules @@ -2,7 +2,7 @@ GLUON_FEEDS='packages routing gluon' OPENWRT_REPO=https://github.com/openwrt/openwrt.git OPENWRT_BRANCH=openwrt-19.07 -OPENWRT_COMMIT=ffd4452f8b241d1d5b5ea8a56206f51702bbd6c5 +OPENWRT_COMMIT=81d0b4a9f431b2b2ca71edca91febedde98994a3 PACKAGES_PACKAGES_REPO=https://github.com/openwrt/packages.git PACKAGES_PACKAGES_BRANCH=openwrt-19.07 @@ -13,4 +13,5 @@ PACKAGES_ROUTING_BRANCH=openwrt-19.07 PACKAGES_ROUTING_COMMIT=101632e153b41238bc19dfd96ba2d23339dbcb76 PACKAGES_GLUON_REPO=https://github.com/freifunk-gluon/packages.git -PACKAGES_GLUON_COMMIT=825aa0c093d6c0b4f81a95cd2320331a5b5adae6 +PACKAGES_GLUON_BRANCH=v2021.1.x +PACKAGES_GLUON_COMMIT=015408e702a5843310e40c2ca664e1903b601204 diff --git a/package/gluon-config-mode-core/luasrc/lib/gluon/config-mode/model/gluon-config-mode/wizard.lua b/package/gluon-config-mode-core/luasrc/lib/gluon/config-mode/model/gluon-config-mode/wizard.lua index dfc4ab4c046826a480ff60b502d289ad50113fca..edfe0bc3a82278695bc5fb44bb401cdd72c3f7fc 100644 --- a/package/gluon-config-mode-core/luasrc/lib/gluon/config-mode/model/gluon-config-mode/wizard.lua +++ b/package/gluon-config-mode-core/luasrc/lib/gluon/config-mode/model/gluon-config-mode/wizard.lua @@ -22,7 +22,7 @@ function f:write() uci:set("gluon-setup-mode", uci:get_first("gluon-setup-mode", "setup_mode"), "configured", true) uci:save("gluon-setup-mode") - os.execute('gluon-reconfigure') + os.execute('exec gluon-reconfigure >/dev/null') f.template = "wizard/reboot" f.package = "gluon-config-mode-core" diff --git a/package/gluon-neighbour-info/src/gluon-neighbour-info.c b/package/gluon-neighbour-info/src/gluon-neighbour-info.c index 6470508ccaaddc4eec283d59a782cc01ecd64d16..119aaddc2a6040a1a8136fd465219b1a31f5e7ea 100644 --- a/package/gluon-neighbour-info/src/gluon-neighbour-info.c +++ b/package/gluon-neighbour-info/src/gluon-neighbour-info.c @@ -69,8 +69,23 @@ void tv_subtract (struct timeval *r, const struct timeval *a, const struct timev } } -ssize_t recvtimeout(int socket, void *buffer, size_t length, int flags, const struct timeval *timeout) { +void resize_recvbuffer(char **recvbuffer, size_t *recvbuffer_len, size_t recvlen) +{ + free(*recvbuffer); + *recvbuffer = malloc(recvlen); + + if (!(*recvbuffer)) { + perror("Could not resize recvbuffer"); + exit(EXIT_FAILURE); + } + + *recvbuffer_len = recvlen; +} + +ssize_t recvtimeout(int socket, char **recvbuffer, size_t *recvbuffer_len, + const struct timeval *timeout) { struct timeval now, timeout_left; + ssize_t recvlen; getclock(&now); tv_subtract(&timeout_left, timeout, &now); @@ -79,18 +94,28 @@ ssize_t recvtimeout(int socket, void *buffer, size_t length, int flags, const st return -1; setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout_left, sizeof(timeout_left)); - return recv(socket, buffer, length, flags); + + recvlen = recv(socket, NULL, 0, MSG_PEEK | MSG_TRUNC); + if (recvlen < 0) + return recvlen; + + if (recvlen > *recvbuffer_len) + resize_recvbuffer(recvbuffer, recvbuffer_len, recvlen); + + return recv(socket, *recvbuffer, *recvbuffer_len, 0); } -int request(const int sock, const struct sockaddr_in6 *client_addr, const char *request, const char *sse, double timeout, unsigned int max_count) { +int request(const int sock, char **recvbuffer, size_t *recvbuffer_len, + const struct sockaddr_in6 *client_addr, const char *request, + const char *sse, double timeout, unsigned int max_count) { ssize_t ret; - char buffer[8192]; unsigned int count = 0; ret = sendto(sock, request, strlen(request), 0, (struct sockaddr *)client_addr, sizeof(struct sockaddr_in6)); if (ret < 0) { perror("Error in sendto()"); + free(*recvbuffer); exit(EXIT_FAILURE); } @@ -105,7 +130,7 @@ int request(const int sock, const struct sockaddr_in6 *client_addr, const char * } do { - ret = recvtimeout(sock, buffer, sizeof(buffer), 0, &tv_timeout); + ret = recvtimeout(sock, recvbuffer, recvbuffer_len, &tv_timeout); if (ret < 0) break; @@ -116,7 +141,7 @@ int request(const int sock, const struct sockaddr_in6 *client_addr, const char * fputs("data: ", stdout); } - fwrite(buffer, sizeof(char), ret, stdout); + fwrite(*recvbuffer, sizeof(char), ret, stdout); if (sse) fputs("\n\n", stdout); @@ -137,6 +162,8 @@ int main(int argc, char **argv) { int sock; struct sockaddr_in6 client_addr = {}; char *request_string = NULL; + char *recvbuffer = NULL; + size_t recvbuffer_len = 0; sock = socket(PF_INET6, SOCK_DGRAM, 0); @@ -243,11 +270,13 @@ int main(int argc, char **argv) { } do { - ret = request(sock, &client_addr, request_string, sse, timeout, max_count); + ret = request(sock, &recvbuffer, &recvbuffer_len, &client_addr, + request_string, sse, timeout, max_count); } while(loop); if (sse) fputs("event: eot\ndata: null\n\n", stdout); + free(recvbuffer); return ret; } diff --git a/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html b/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html index 861c13a43f9fa09545bb4fa5a8a74172c587cbf5..6957599f37803637d3a14c89e4630c1442874fa3 100644 --- a/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html +++ b/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html @@ -1,7 +1,11 @@ <%- + local iwinfo = require 'iwinfo' local ubus = require 'ubus' local unistd = require 'posix.unistd' local util = require 'gluon.util' + local wireless = require 'gluon.wireless' + + local uci = require('simple-uci').cursor() local translations = {} local site_i18n = i18n 'gluon-site' @@ -29,17 +33,31 @@ local mesh = get_mesh() - local function get_interfaces() - local uconn = ubus.connect() - if not uconn then - error('failed to connect to ubus') - end + local function get_interfaces(uconn) local interfaces = util.get_mesh_devices(uconn) - ubus.close(uconn) table.sort(interfaces) return interfaces end + local function get_radios() + local ret = {} + + wireless.foreach_radio(uci, function(radio) + local channel = iwinfo.nl80211.channel(wireless.find_phy(radio)) + if channel then + table.insert(ret, { + name = radio['.name'], + channel = channel, + }) + end + end) + table.sort(ret, function(a, b) + return a.name < b.name + end) + + return ret + end + local function is_wireless(iface) while true do local pattern = '/sys/class/net/' .. iface .. '/lower_*' @@ -52,7 +70,16 @@ return unistd.access('/sys/class/net/' .. iface .. '/wireless') ~= nil end - local interfaces = get_interfaces() + local uconn = ubus.connect() + if not uconn then + error('failed to connect to ubus') + end + + local interfaces = get_interfaces(uconn) + + ubus.close(uconn) + + local radios = get_radios() local function sorted(t) t = {unpack(t)} @@ -66,12 +93,17 @@ local function formatBits(bits) local units = {[0]='', 'k', 'M', 'G'} + local unit = 0 - local pow = math.floor(math.log(math.max(math.abs(bits), 1)) / math.log(1000)) - local known_pow = math.min(pow, #units) + for i = 1, #units do + if math.abs(bits) < 1000 then + break + end + unit = i + bits = bits / 1000 + end - local significand = bits/(1000^known_pow) - return string.format('%g %sbit', significand, units[known_pow]) + return string.format('%g %sbit', bits, units[unit]) end local function statistics(key, format) @@ -135,11 +167,11 @@ <% if nodeinfo.network.mesh_vpn.bandwidth_limit.enabled then -%> <dt><%:Bandwidth limit%></dt> <dd> - <% if nodeinfo.network.mesh_vpn.bandwidth_limit.egress then -%> - ▲ <%| formatBits(nodeinfo.network.mesh_vpn.bandwidth_limit.egress*1000) %>/s <%:upstream%><br /> - <%- end %> <% if nodeinfo.network.mesh_vpn.bandwidth_limit.ingress then -%> - ▼ <%| formatBits(nodeinfo.network.mesh_vpn.bandwidth_limit.ingress*1000) %>/s <%:downstream%> + ▼ <%| formatBits(nodeinfo.network.mesh_vpn.bandwidth_limit.ingress*1000) %>/s <%:downstream%><br /> + <%- end %> + <% if nodeinfo.network.mesh_vpn.bandwidth_limit.egress then -%> + ▲ <%| formatBits(nodeinfo.network.mesh_vpn.bandwidth_limit.egress*1000) %>/s <%:upstream%> <%- end %> </dd> <%- end %> @@ -190,11 +222,17 @@ <tr><th><%:Wireless 2.4 GHz%></th><td><%= statistics('clients/wifi24') %></td></tr> <tr><th><%:Wireless 5 GHz%></th><td><%= statistics('clients/wifi5') %></td></tr> </table> - <div id="radios" style="display: none"> + <% if radios[1] then -%> <h3><%:Radios%></h3> - <table id="radio-devices"> + <table> + <% for _, radio in ipairs(radios) do -%> + <tr> + <th><%| radio.name %></th> + <td><%| translatef('Channel %u', radio.channel) %></td> + </tr> + <%- end %> </table> - </div> + <%- end %> <h3><%:Traffic%></h3> <table> diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/static/status-page.js b/package/gluon-status-page/files/lib/gluon/status-page/www/static/status-page.js index 3fe35c37a96d42a199f6dcf7c382ef83c33765f5..21c3c692925fa2d789916114aab4abfa980cfc7e 100644 --- a/package/gluon-status-page/files/lib/gluon/status-page/www/static/status-page.js +++ b/package/gluon-status-page/files/lib/gluon/status-page/www/static/status-page.js @@ -1 +1 @@ -"use strict";!function(){var r=JSON.parse(document.body.getAttribute("data-translations"));function i(t,e){return t.toFixed(e).replace(/\./,r["."])}function o(t,e){e--;for(var n=t;10<=n&&0<e;n/=10)e--;return i(t,e)}function a(t){return function(t,e,n){var i=0;if(void 0===n)return"- ";for(;e<n&&i<t.length-1;)n/=e,i++;return(n=o(n,3))+" "+t[i]}(["","K","M","G","T"],1024,t)}String.prototype.sprintf=function(){var t=0,e=arguments;return this.replace(/%s/g,function(){return e[t++]})};var s={id:function(t){return t},decimal:function(t){return i(t,2)},percent:function(t){return r["%s used"].sprintf(o(100*t,3)+"%")},memory:function(t){t=1-t.available/t.total;return s.percent(t)},time:function(t){var e=Math.round(t/60),n=Math.floor(e/1440),i=Math.floor(e%1440/60),e=Math.floor(e%60),t="";return 1===n?t+=r["1 day"]+", ":1<n&&(t+=r["%s days"].sprintf(n)+", "),t+=i+":",e<10&&(t+="0"),t+=e},packetsDiff:function(t,e,n){if(0<n)return n=(t-e)/n,r["%s packets/s"].sprintf(i(n,0))},bytesDiff:function(t,e,n){if(0<n)return a(8*((t-e)/n))+"bps"},bytes:function(t){return a(t)+"B"},neighbour:function(t){if(!t)return"";for(var e in c){var n=c[e].lookup_neigh(t);if(n)return"via "+n.get_hostname()+" ("+e+")"}return"via "+t+" (unknown iface)"}};function l(e,t){return t.split("/").forEach(function(t){e=e&&e[t]}),e}function d(t,e){var n=new EventSource(t),i={};n.onmessage=function(t){t=JSON.parse(t.data);e(t,i),i=t},n.onerror=function(){n.close(),window.setTimeout(function(){d(t,e)},3e3)}}var x,k=document.body.getAttribute("data-node-address");try{x=JSON.parse(document.body.getAttribute("data-node-location"))}catch(t){}function t(t){var e=document.getElementById("mesh-vpn");if(t){e.style.display="";for(var i=document.getElementById("mesh-vpn-peers");i.lastChild;)i.removeChild(i.lastChild);t=function e(n,i){return Object.keys(i.peers||{}).forEach(function(t){n.push([t,i.peers[t]])}),Object.keys(i.groups||{}).forEach(function(t){e(n,i.groups[t])}),n}([],t);t.sort(),t.forEach(function(t){var e=document.createElement("tr"),n=document.createElement("th");n.textContent=t[0],e.appendChild(n);n=document.createElement("td");t[1]?n.textContent=r.connected+" ("+s.time(t[1].established)+")":n.textContent=r["not connected"],e.appendChild(n),i.appendChild(e)})}else e.style.display="none"}function e(t){var e=document.getElementById("radios");if(t){e.style.display="";for(var i=document.getElementById("radio-devices");i.lastChild;)i.removeChild(i.lastChild);t.sort(function(t,e){return t.phy-e.phy}),t.forEach(function(t){var e=document.createElement("tr"),n=document.createElement("th");n.textContent="phy"+t.phy,e.appendChild(n);n=document.createElement("td");n.innerHTML=t.frequency+" MHz<br />Channel "+(2484===(t=t.frequency)?14:2412<=t&&t<=2472?(t-2407)/5:5160<=t&&t<=5885?(t-5e3)/5:"unknown"),e.appendChild(n),i.appendChild(e)})}else e.style.display="none"}var n=document.querySelectorAll("[data-statistics]");d("/cgi-bin/dyn/statistics",function(o,a){var c=o.uptime-a.uptime;n.forEach(function(t){var e=t.getAttribute("data-statistics"),n=t.getAttribute("data-format"),i=l(a,e),e=l(o,e);try{var r=s[n](e,i,c);void 0!==r&&(t.textContent=r)}catch(t){console.error(t)}});try{t(o.mesh_vpn)}catch(t){console.error(t)}try{e(o.wireless)}catch(t){console.error(t)}});var c={};function A(n){var i=document.createElement("canvas"),r=i.getContext("2d"),o=null;return{canvas:i,highlight:!1,resize:function(t,e){try{r.getImageData(0,0,t,e)}catch(t){}i.width=t,i.height=e},draw:function(t,e){e=e(o);r.clearRect(t,0,5,i.height),e&&(t=t,e=e,r.beginPath(),r.fillStyle=n,r.arc(t,e,1.2,0,2*Math.PI,!1),r.closePath(),r.fill())},set:function(t){o=t}}}function h(){var c=-100,s=0,n=0,i=[],l=document.createElement("canvas");l.className="signalgraph",l.height=200;var u=l.getContext("2d");function t(){l.width=l.clientWidth,i.forEach(function(t){t.resize(l.width,l.height)})}function r(){var e;0!==l.clientWidth&&(l.width!==l.clientWidth&&t(),u.clearRect(0,0,l.width,l.height),e=!1,i.forEach(function(t){t.highlight&&(e=!0)}),u.save(),i.forEach(function(t){e&&(u.globalAlpha=.2),t.highlight&&(u.globalAlpha=1),t.draw(n,function(t){return e=t,n=c,i=s,t=l.height,(1-(e-n)/(i-n))*t;var e,n,i}),u.drawImage(t.canvas,0,0)}),u.restore(),u.save(),u.beginPath(),u.strokeStyle="rgba(255, 180, 0, 0.15)",u.lineWidth=5,u.moveTo(n+2.5,0),u.lineTo(n+2.5,l.height),u.stroke(),function(){var t=Math.floor(l.height/40);u.save(),u.lineWidth=.5,u.strokeStyle="rgba(0, 0, 0, 0.25)",u.fillStyle="rgba(0, 0, 0, 0.5)",u.textAlign="end",u.textBaseline="bottom",u.beginPath();for(var e,n,i,r=0;r<t;r++){var o=l.height-40*r;u.moveTo(0,o-.5),u.lineTo(l.width,o-.5);var a=Math.round((e=o,n=c,i=s,a=l.height,(n*e+i*(a-e))/a))+" dBm";u.save(),u.strokeStyle="rgba(255, 255, 255, 0.9)",u.lineWidth=4,u.miterLimit=2,u.strokeText(a,l.width-5,o-2.5),u.fillText(a,l.width-5,o-2.5),u.restore()}u.stroke(),u.strokeStyle="rgba(0, 0, 0, 0.83)",u.lineWidth=1.5,u.strokeRect(.5,.5,l.width-1,l.height-1),u.restore()}())}t(),window.addEventListener("resize",r);var o=0;return window.requestAnimationFrame(function t(e){40<e-o&&(r(),n=(n+1)%l.width,o=e),window.requestAnimationFrame(t)}),{el:l,addSignal:function(t){i.push(t),t.resize(l.width,l.height)},removeSignal:function(t){i.splice(i.indexOf(t),1)}}}function f(t,e,n,i){var r,o=t.table.firstElementChild,a=t.table.insertRow(),c=a.insertCell();c.setAttribute("data-label",o.children[0].textContent),t.wireless&&((r=document.createElement("span")).textContent="⬤ ",r.style.color=n,c.appendChild(r));var s=document.createElement("span");s.textContent=e,c.appendChild(s);var l={};for(var u,d,h,f,g,v,m,p,b,y=0;y<o.children.length;y++)u=o.children[y],f=h=d=void 0,(f=u.getAttribute("data-key"))&&(d=u.getAttribute("data-suffix")||"",(h=a.insertCell()).textContent="-",h.setAttribute("data-label",u.textContent),l[f]={td:h,suffix:d});function C(){b&&window.clearTimeout(b),b=window.setTimeout(function(){p&&t.signalgraph.removeSignal(p),a.parentNode.removeChild(a),i()},6e4)}function E(t){t=function(t){"::"==(t="::"==t.slice(0,2)?"0"+t:t).slice(-2)&&(t+="0");var n=(t=t.split(":")).length,i=[];return t.forEach(function(t,e){if(""===t)for(;n++<=8;)i.push(0);else/^[a-f0-9]{1,4}$/i.test(t)&&i.push(parseInt(t,16))}),i}(t);if(t){var e="";return t.forEach(function(t){e+=("0000000000000000"+t.toString(2)).slice(-16)}),e}}function w(t){var i=E(k);if(t&&t[0]){(t=t.map(function(t){var e=E(t);if(!e)return[-1];var n=0;return[n=i?function(t,e){for(var n=0;n<t.length&&n<e.length&&t[n]===e[n];n++);return n}(i,e):n,e,t]})).sort(function(t,e){return t[0]<e[0]?1:t[0]>e[0]||t[1]<e[1]?-1:t[1]>e[1]?1:0});t=t[0][2];return t&&!/^fe80:/i.test(t)?t:void 0}}return t.wireless&&((g=a.insertCell()).textContent="-",g.setAttribute("data-label",o.children[Object.keys(l).length+1].textContent),(v=a.insertCell()).textContent="-",v.setAttribute("data-label",o.children[Object.keys(l).length+2].textContent),(m=a.insertCell()).textContent="-",m.setAttribute("data-label",o.children[Object.keys(l).length+3].textContent),p=A(n),t.signalgraph.addSignal(p)),a.onmouseenter=function(){a.classList.add("highlight"),p&&(p.highlight=!0)},a.onmouseleave=function(){a.classList.remove("highlight"),p&&(p.highlight=!1)},C(),{get_hostname:function(){return s.textContent},update_nodeinfo:function(t){var e,n,i,r,o=w(t.network.addresses);o&&("span"===s.nodeName.toLowerCase()&&(r=s,s=document.createElement("a"),r.parentNode.replaceChild(s,r)),s.href="http://["+o+"]/"),s.textContent=t.hostname,x&&t.location&&(e=x.latitude,n=x.longitude,i=t.location.latitude,r=t.location.longitude,o=Math.PI/180,t=(i*=o)-(e*=o),n=(r*=o)-(n*=o),i=Math.sin(t/2)*Math.sin(t/2)+Math.sin(n/2)*Math.sin(n/2)*Math.cos(e)*Math.cos(i),i=6372.8*(2*Math.asin(Math.sqrt(i))),v.textContent=Math.round(1e3*i)+" m"),C()},update_mesh:function(n){Object.keys(l).forEach(function(t){var e=l[t];e.td.textContent=n[t]+e.suffix}),C()},update_wifi:function(t){g.textContent=t.signal,m.textContent=Math.round(t.inactive/1e3)+" s",a.classList.toggle("inactive",200<t.inactive),p.set(200<t.inactive?null:t.signal),C()}}}function u(t,e,n){var i,o={};n&&(i=h(),t.appendChild(i.el));var r={table:t.firstElementChild,signalgraph:i,ifname:e,wireless:n},a=!1,c={},s=[];function l(){var t;a||(a=!0,(t=new EventSource("/cgi-bin/dyn/neighbours-nodeinfo?"+encodeURIComponent(e))).addEventListener("neighbour",function(t){try{var n=JSON.parse(t.data);i=[],r=n.network.mesh,Object.keys(r).forEach(function(t){var e=r[t].interfaces;Object.keys(e).forEach(function(t){e[t].forEach(function(t){i.push(t)})})}),i.forEach(function(t){var e=o[t];if(e){delete c[t];try{e.update_nodeinfo(n)}catch(t){console.error(t)}}})}catch(t){console.error(t)}var i,r},!1),t.onerror=function(){t.close(),a=!1,Object.keys(c).forEach(function(t){0<c[t]&&(c[t]--,l())})})}function u(t){var e=o[t];return e||(c[t]=3,e=o[t]=f(r,t,(s=s[0]?s:["#396AB1","#DA7C30","#3E9651","#CC2529","#535154","#6B4C9A","#922428","#948B3D"]).shift(),function(){delete c[t],delete o[t]}),l()),e}return n&&d("/cgi-bin/dyn/stations?"+encodeURIComponent(e),function(n){Object.keys(n).forEach(function(t){var e=n[t];u(t).update_wifi(e)})}),{get_neigh:u,lookup_neigh:function(t){return o[t]}}}document.querySelectorAll("[data-interface]").forEach(function(t){var e=t.getAttribute("data-interface"),n=(t.getAttribute("data-interface-address"),!!t.getAttribute("data-interface-wireless"));c[e]=u(t,e,n)});var g=document.body.getAttribute("data-mesh-provider");g&&d(g,function(i){Object.keys(i).forEach(function(t){var e=i[t],n=c[e.ifname];n&&n.get_neigh(t).update_mesh(e)})})}(); \ No newline at end of file +"use strict";!function(){var i=JSON.parse(document.body.getAttribute("data-translations"));function r(t,e){return t.toFixed(e).replace(/\./,i["."])}function a(t,e){e--;for(var n=t;10<=n&&0<e;n/=10)e--;return r(t,e)}function o(t){return function(t,e,n){var r=0;if(void 0===n)return"- ";for(;e<n&&r<t.length-1;)n/=e,r++;return(n=a(n,3))+" "+t[r]}(["","K","M","G","T"],1024,t)}String.prototype.sprintf=function(){var t=0,e=arguments;return this.replace(/%s/g,function(){return e[t++]})};var u={id:function(t){return t},decimal:function(t){return r(t,2)},percent:function(t){return i["%s used"].sprintf(a(100*t,3)+"%")},memory:function(t){t=1-t.available/t.total;return u.percent(t)},time:function(t){var e=Math.round(t/60),n=Math.floor(e/1440),r=Math.floor(e%1440/60),e=Math.floor(e%60),t="";return 1===n?t+=i["1 day"]+", ":1<n&&(t+=i["%s days"].sprintf(n)+", "),t+=r+":",e<10&&(t+="0"),t+=e},packetsDiff:function(t,e,n){if(0<n)return n=(t-e)/n,i["%s packets/s"].sprintf(r(n,0))},bytesDiff:function(t,e,n){if(0<n)return o(8*((t-e)/n))+"bps"},bytes:function(t){return o(t)+"B"},neighbour:function(t){if(!t)return"";for(var e in c){var n=c[e].lookup_neigh(t);if(n){var r=document.createElement("span");r.appendChild(document.createTextNode("via "));var i=document.createElement("a");return i.href="http://["+n.get_addr()+"]/",i.textContent=n.get_hostname(),r.appendChild(i),r.appendChild(document.createTextNode(" ("+e+")")),r}}return"via "+t+" (unknown iface)"}};function s(e,t){return t.split("/").forEach(function(t){e=e&&e[t]}),e}function d(t,e){var n=new EventSource(t),r={};n.onmessage=function(t){t=JSON.parse(t.data);e(t,r),r=t},n.onerror=function(){n.close(),window.setTimeout(function(){d(t,e)},3e3)}}var x,k=document.body.getAttribute("data-node-address");try{x=JSON.parse(document.body.getAttribute("data-node-location"))}catch(t){}function t(t){var e=document.getElementById("mesh-vpn");if(t){e.style.display="";for(var r=document.getElementById("mesh-vpn-peers");r.lastChild;)r.removeChild(r.lastChild);t=function e(n,r){return Object.keys(r.peers||{}).forEach(function(t){n.push([t,r.peers[t]])}),Object.keys(r.groups||{}).forEach(function(t){e(n,r.groups[t])}),n}([],t);t.sort(),t.forEach(function(t){var e=document.createElement("tr"),n=document.createElement("th");n.textContent=t[0],e.appendChild(n);n=document.createElement("td");t[1]?n.textContent=i.connected+" ("+u.time(t[1].established)+")":n.textContent=i["not connected"],e.appendChild(n),r.appendChild(e)})}else e.style.display="none"}var e=document.querySelectorAll("[data-statistics]");d("/cgi-bin/dyn/statistics",function(a,o){var c=a.uptime-o.uptime;e.forEach(function(t){var e=t.getAttribute("data-statistics"),n=t.getAttribute("data-format"),r=s(o,e),e=s(a,e);try{var i=u[n](e,r,c);"object"==typeof i?(t.lastChild&&t.removeChild(t.lastChild),t.appendChild(i)):t.textContent=i}catch(t){console.error(t)}});try{t(a.mesh_vpn)}catch(t){console.error(t)}});var c={};function A(n){var r=document.createElement("canvas"),i=r.getContext("2d"),a=null;return{canvas:r,highlight:!1,resize:function(t,e){var n;try{n=i.getImageData(0,0,t,e)}catch(t){}r.width=t,r.height=e,n&&i.putImageData(n,0,0)},draw:function(t,e){e=e(a);i.clearRect(t,0,5,r.height),e&&(t=t,e=e,i.beginPath(),i.fillStyle=n,i.arc(t,e,1.2,0,2*Math.PI,!1),i.closePath(),i.fill())},set:function(t){a=t}}}function h(){var i=-100,a=0,n=0,r=[],o=document.createElement("canvas");o.className="signalgraph",o.height=200;var c=o.getContext("2d");function t(){o.width=o.clientWidth,r.forEach(function(t){t.resize(o.width,o.height)})}function u(){var e;0!==o.clientWidth&&(o.width!==o.clientWidth&&t(),c.clearRect(0,0,o.width,o.height),e=!1,r.forEach(function(t){t.highlight&&(e=!0)}),c.save(),r.forEach(function(t){e&&(c.globalAlpha=.2),t.highlight&&(c.globalAlpha=1),t.draw(n,function(t){return e=o.height,(1-(t-i)/(a-i))*e;var e}),c.drawImage(t.canvas,0,0)}),c.restore(),c.save(),c.beginPath(),c.strokeStyle="rgba(255, 180, 0, 0.15)",c.lineWidth=5,c.moveTo(n+2.5,0),c.lineTo(n+2.5,o.height),c.stroke(),function(){var t=Math.floor(o.height/40);c.save(),c.lineWidth=.5,c.strokeStyle="rgba(0, 0, 0, 0.25)",c.fillStyle="rgba(0, 0, 0, 0.5)",c.textAlign="end",c.textBaseline="bottom",c.beginPath();for(var e=0;e<t;e++){var n=o.height-40*e;c.moveTo(0,n-.5),c.lineTo(o.width,n-.5);var r=Math.round((r=o.height,(i*n+a*(r-n))/r))+" dBm";c.save(),c.strokeStyle="rgba(255, 255, 255, 0.9)",c.lineWidth=4,c.miterLimit=2,c.strokeText(r,o.width-5,n-2.5),c.fillText(r,o.width-5,n-2.5),c.restore()}c.stroke(),c.strokeStyle="rgba(0, 0, 0, 0.83)",c.lineWidth=1.5,c.strokeRect(.5,.5,o.width-1,o.height-1),c.restore()}())}t(),window.addEventListener("resize",u);var s=0;return window.requestAnimationFrame(function t(e){40<e-s&&(u(),n=(n+1)%o.width,s=e),window.requestAnimationFrame(t)}),{el:o,addSignal:function(t){r.push(t),t.resize(o.width,o.height)},removeSignal:function(t){r.splice(r.indexOf(t),1)}}}function f(t,o,e,n){var r,i=t.table.firstElementChild,a=t.table.insertRow(),c=a.insertCell();c.setAttribute("data-label",i.children[0].textContent),t.wireless&&((r=document.createElement("span")).textContent="⬤ ",r.style.color=e,c.appendChild(r));var u=document.createElement("span");u.textContent=o,c.appendChild(u);var s={};for(var l,d,h,f,g,v,p,m,b,C=0;C<i.children.length;C++)l=i.children[C],f=h=d=void 0,(f=l.getAttribute("data-key"))&&(d=l.getAttribute("data-suffix")||"",(h=a.insertCell()).textContent="-",h.setAttribute("data-label",l.textContent),s[f]={td:h,suffix:d});function y(){b&&window.clearTimeout(b),b=window.setTimeout(function(){m&&t.signalgraph.removeSignal(m),a.parentNode.removeChild(a),n()},6e4)}function w(t){t=function(t){"::"==(t="::"==t.slice(0,2)?"0"+t:t).slice(-2)&&(t+="0");for(var e=t.split(":"),n=e.length,r=[],i=0;i<e.length;i++){var a=e[i];if(""===a)for(;n++<=8;)r.push(0);else{if(!/^[a-f0-9]{1,4}$/i.test(a))return;r.push(parseInt(a,16))}}return r}(t);if(t){var e="";return t.forEach(function(t){e+=("0000000000000000"+t.toString(2)).slice(-16)}),e}}function E(t){var r=w(k);if(t&&t[0]){(t=t.map(function(t){var e=w(t);if(!e)return[-1];var n=0;return[n=r?function(t,e){for(var n=0;n<t.length&&n<e.length&&t[n]===e[n];n++);return n}(r,e):n,e,t]})).sort(function(t,e){return t[0]<e[0]?1:t[0]>e[0]||t[1]<e[1]?-1:t[1]>e[1]?1:0});t=t[0][2];return t&&!/^fe80:/i.test(t)?t:void 0}}return t.wireless&&((g=a.insertCell()).textContent="-",g.setAttribute("data-label",i.children[Object.keys(s).length+1].textContent),(v=a.insertCell()).textContent="-",v.setAttribute("data-label",i.children[Object.keys(s).length+2].textContent),(p=a.insertCell()).textContent="-",p.setAttribute("data-label",i.children[Object.keys(s).length+3].textContent),m=A(e),t.signalgraph.addSignal(m)),a.onmouseenter=function(){a.classList.add("highlight"),m&&(m.highlight=!0)},a.onmouseleave=function(){a.classList.remove("highlight"),m&&(m.highlight=!1)},y(),{get_hostname:function(){return u.textContent},get_addr:function(){return o},update_nodeinfo:function(t){var e,n,r,i,a;(o=E(t.network.addresses))&&("span"===u.nodeName.toLowerCase()&&(a=u,u=document.createElement("a"),a.parentNode.replaceChild(u,a)),u.href="http://["+o+"]/"),u.textContent=t.hostname,x&&t.location&&(e=x.latitude,n=x.longitude,r=t.location.latitude,i=t.location.longitude,a=Math.PI/180,t=(r*=a)-(e*=a),n=(i*=a)-(n*=a),r=Math.sin(t/2)*Math.sin(t/2)+Math.sin(n/2)*Math.sin(n/2)*Math.cos(e)*Math.cos(r),r=6372.8*(2*Math.asin(Math.sqrt(r))),v.textContent=Math.round(1e3*r)+" m"),y()},update_mesh:function(n){Object.keys(s).forEach(function(t){var e=s[t];e.td.textContent=n[t]+e.suffix}),y()},update_wifi:function(t){g.textContent=t.signal,p.textContent=Math.round(t.inactive/1e3)+" s",a.classList.toggle("inactive",200<t.inactive),m.set(200<t.inactive?null:t.signal),y()}}}function l(t,e,n){var r,a={};n&&(r=h(),t.appendChild(r.el));var i={table:t.firstElementChild,signalgraph:r,ifname:e,wireless:n},o=!1,c={},u=[];function s(){var t;o||(o=!0,(t=new EventSource("/cgi-bin/dyn/neighbours-nodeinfo?"+encodeURIComponent(e))).addEventListener("neighbour",function(t){try{var n=JSON.parse(t.data);r=[],i=n.network.mesh,Object.keys(i).forEach(function(t){var e=i[t].interfaces;Object.keys(e).forEach(function(t){e[t].forEach(function(t){r.push(t)})})}),r.forEach(function(t){var e=a[t];if(e){delete c[t];try{e.update_nodeinfo(n)}catch(t){console.error(t)}}})}catch(t){console.error(t)}var r,i},!1),t.onerror=function(){t.close(),o=!1,Object.keys(c).forEach(function(t){0<c[t]&&(c[t]--,s())})})}function l(t){var e=a[t];return e||(c[t]=3,e=a[t]=f(i,t,(u=u[0]?u:["#396AB1","#DA7C30","#3E9651","#CC2529","#535154","#6B4C9A","#922428","#948B3D"]).shift(),function(){delete c[t],delete a[t]}),s()),e}return n&&d("/cgi-bin/dyn/stations?"+encodeURIComponent(e),function(n){Object.keys(n).forEach(function(t){var e=n[t];l(t).update_wifi(e)})}),{get_neigh:l,lookup_neigh:function(t){return a[t]}}}document.querySelectorAll("[data-interface]").forEach(function(t){var e=t.getAttribute("data-interface"),n=(t.getAttribute("data-interface-address"),!!t.getAttribute("data-interface-wireless"));c[e]=l(t,e,n)});var n=document.body.getAttribute("data-mesh-provider");n&&d(n,function(r){Object.keys(r).forEach(function(t){var e=r[t],n=c[e.ifname];n&&n.get_neigh(t).update_mesh(e)})})}(); \ No newline at end of file diff --git a/package/gluon-status-page/i18n/de.po b/package/gluon-status-page/i18n/de.po index e86b174bee7cb616c8be99ba0b063217f0e4a739..27801e197c475f6f3a152a80c3c9a12069ab4e36 100644 --- a/package/gluon-status-page/i18n/de.po +++ b/package/gluon-status-page/i18n/de.po @@ -31,8 +31,8 @@ msgstr "Automatische Updates" msgid "Bandwidth limit" msgstr "Bandbreitenlimit" -msgid "Channel" -msgstr "Kanal" +msgid "Channel %u" +msgstr "Kanal %u" msgid "Clients" msgstr "Clients" diff --git a/package/gluon-status-page/i18n/gluon-status-page.pot b/package/gluon-status-page/i18n/gluon-status-page.pot index 5a8008fdfa7d59965f085ad1a678b4538b5bb75a..50d7d6bee78208c0b16f4de623cce9564ee11d02 100644 --- a/package/gluon-status-page/i18n/gluon-status-page.pot +++ b/package/gluon-status-page/i18n/gluon-status-page.pot @@ -22,7 +22,7 @@ msgstr "" msgid "Bandwidth limit" msgstr "" -msgid "Channel" +msgid "Channel %u" msgstr "" msgid "Clients" diff --git a/package/gluon-status-page/javascript/status-page.js b/package/gluon-status-page/javascript/status-page.js index 4c44e7ed53493ef6cad3b24c781667b4007d4572..7581dc7fb9a2ca88e180ebb29cff19278ec83d2d 100644 --- a/package/gluon-status-page/javascript/status-page.js +++ b/package/gluon-status-page/javascript/status-page.js @@ -121,7 +121,15 @@ var neigh = iface.lookup_neigh(addr); if (!neigh) continue; - return 'via ' + neigh.get_hostname() + ' (' + i + ')'; + + var span = document.createElement('span'); + span.appendChild(document.createTextNode('via ')); + var a = document.createElement('a'); + a.href = 'http://[' + neigh.get_addr() + ']/'; + a.textContent = neigh.get_hostname(); + span.appendChild(a); + span.appendChild(document.createTextNode(' (' + i + ')')); + return span; } return 'via ' + addr + ' (unknown iface)'; @@ -208,50 +216,6 @@ }); } - function update_radios(wireless) { - function channel(frequency) { - if (frequency===2484) - return 14 - - if (2412<=frequency && frequency<=2472) - return (frequency-2407)/5 - - if (5160<=frequency && frequency<=5885) - return (frequency-5000)/5 - - return 'unknown' - } - - var div = document.getElementById('radios'); - if (!wireless) { - div.style.display = 'none'; - return; - } - div.style.display = ''; - - var table = document.getElementById('radio-devices'); - while (table.lastChild) - table.removeChild(table.lastChild); - - wireless.sort(function (a, b) { - return a.phy - b.phy; - }); - - wireless.forEach(function (radio) { - var tr = document.createElement('tr'); - - var th = document.createElement('th'); - th.textContent = "phy" + radio.phy; - tr.appendChild(th); - - var td = document.createElement('td'); - td.innerHTML = radio.frequency + " MHz<br />Channel " + channel(radio.frequency); - tr.appendChild(td); - - table.appendChild(tr); - }); - } - var statisticsElems = document.querySelectorAll('[data-statistics]'); add_event_source('/cgi-bin/dyn/statistics', function(data, dataPrev) { @@ -264,9 +228,16 @@ var valuePrev = resolve_key(dataPrev, stat); var value = resolve_key(data, stat); try { - var text = formats[format](value, valuePrev, diff); - if (text !== undefined) - elem.textContent = text; + var format_result = formats[format](value, valuePrev, diff); + switch (typeof format_result) { + case "object": + if (elem.lastChild) + elem.removeChild(elem.lastChild); + elem.appendChild(format_result); + break; + default: + elem.textContent = format_result; + } } catch (e) { console.error(e); } @@ -277,11 +248,6 @@ } catch (e) { console.error(e); } - try { - update_radios(data.wireless); - } catch (e) { - console.error(e); - } }) function haversine(lat1, lon1, lat2, lon2) { @@ -319,7 +285,7 @@ 'resize': function(w, h) { var lastImage; try { - ctx.getImageData(0, 0, w, h); + lastImage = ctx.getImageData(0, 0, w, h); } catch (e) {} canvas.width = w; canvas.height = h; @@ -492,6 +458,7 @@ } var hostname = document.createElement("span"); + var addr; hostname.textContent = addr; tdHostname.appendChild(hostname); @@ -552,13 +519,13 @@ el.classList.add("highlight"); if (signal) signal.highlight = true; - } + }; el.onmouseleave = function () { - el.classList.remove("highlight") + el.classList.remove("highlight"); if (signal) signal.highlight = false; - } + }; var timeout; @@ -586,7 +553,8 @@ var n = parts.length; var groups = []; - parts.forEach(function(part, i) { + for (var i = 0; i < parts.length; i++) { + var part = parts[i]; if (part === '') { while (n++ <= 8) groups.push(0); @@ -596,7 +564,7 @@ groups.push(parseInt(part, 16)); } - }); + }; return groups; } @@ -664,8 +632,11 @@ 'get_hostname': function() { return hostname.textContent; }, + 'get_addr': function() { + return addr; + }, 'update_nodeinfo': function(nodeinfo) { - var addr = choose_address(nodeinfo.network.addresses); + addr = choose_address(nodeinfo.network.addresses); if (addr) { if (hostname.nodeName.toLowerCase() === 'span') { var oldHostname = hostname; diff --git a/package/gluon-status-page/luasrc/lib/gluon/status-page/controller/status-page.lua b/package/gluon-status-page/luasrc/lib/gluon/status-page/controller/status-page.lua index ceb5d855273acba80d8e11468ee5421db7f99e26..80c5e50a4e03f882828dfdada1edefda6d0029d1 100644 --- a/package/gluon-status-page/luasrc/lib/gluon/status-page/controller/status-page.lua +++ b/package/gluon-status-page/luasrc/lib/gluon/status-page/controller/status-page.lua @@ -61,7 +61,7 @@ local function match(a, b, n) end entry({}, call(function(http, renderer) - local nodeinfo = json.parse(util.exec('exec gluon-neighbour-info -d ::1 -p 1001 -t 1 -c 1 -r nodeinfo')) + local nodeinfo = json.parse(util.exec('exec gluon-neighbour-info -d ::1 -p 1001 -t 3 -c 1 -r nodeinfo')) local node_ip = parse_ip(http:getenv('SERVER_ADDR')) if node_ip and ( diff --git a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade.html b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade.html index 31555f16530b6a12c9a3131474e98850d40c88f5..7778be4a6c9eb8a01b8232557293c58a4beb8135 100644 --- a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade.html +++ b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade.html @@ -44,7 +44,6 @@ $Id$ <div class="gluon-page-actions"> <input type="hidden" name="step" value="2" /> - <input type="hidden" name="token" value="<%=token%>" /> <input class="gluon-button gluon-button-submit" type="submit" value="<%:Upload image%>" /> </div> </form> diff --git a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html index 92c25a632910f5ad953672013476c2efdff284cd..9733132fa9ec7ca77d5d64ae4d198bc25e3f4a9c 100644 --- a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html +++ b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html @@ -49,13 +49,11 @@ You may obtain a copy of the License at <form method="post" enctype="multipart/form-data" action="<%|url(request)%>" style="display:inline"> <input type="hidden" name="step" value="3" /> <input type="hidden" name="keepcfg" value="<%=keepconfig and "1" or "0"%>" /> - <input type="hidden" name="token" value="<%=token%>" /> <input class="gluon-button gluon-button-submit" type="submit" value="<%:Continue%>" /> </form> <form method="post" enctype="multipart/form-data" action="<%|url(request)%>" style="display:inline"> <input type="hidden" name="step" value="1" /> <input type="hidden" name="keepcfg" value="<%=keepconfig and "1" or "0"%>" /> - <input type="hidden" name="token" value="<%=token%>" /> <input class="gluon-button gluon-button-reset" type="submit" value="<%:Cancel%>" /> </form> </div> diff --git a/package/gluon-web-model/files/lib/gluon/web/view/model/form.html b/package/gluon-web-model/files/lib/gluon/web/view/model/form.html index 06270be3a576eb1a4aac23a77da9f1f401c20bd2..d222dde2c9c07bd96d5dbdac50ac83a2862fe9a5 100644 --- a/package/gluon-web-model/files/lib/gluon/web/view/model/form.html +++ b/package/gluon-web-model/files/lib/gluon/web/view/model/form.html @@ -1,5 +1,4 @@ <form method="post" enctype="multipart/form-data" action="<%|url(request)%>" data-update="reset"> - <input type="hidden" name="token" value="<%=token%>" /> <input type="hidden" name="<%=id%>" value="1" /> <div class="gluon-form" id="form-<%=id%>"> diff --git a/package/gluon-web-osm/files/lib/gluon/web/view/model/osm/map.html b/package/gluon-web-osm/files/lib/gluon/web/view/model/osm/map.html index 2caa3f379161d18a03c16cdf48341b57a9cd4581..a2822cd4420bc691c43fe9851152ef23edbdee7f 100644 --- a/package/gluon-web-osm/files/lib/gluon/web/view/model/osm/map.html +++ b/package/gluon-web-osm/files/lib/gluon/web/view/model/osm/map.html @@ -1,6 +1,7 @@ <div id="<%=id%>" class="gluon-osm-map" style="display: none"></div> <script type="text/javascript" src="/static/gluon-web-osm.js"></script> <script type="text/javascript"> + //<![CDATA[ (function() { var elMap = document.getElementById(<%=json(id)%>); var wrapper = elMap.parentNode; @@ -41,4 +42,5 @@ }); }); })(); + //]]> </script> diff --git a/package/gluon-web-osm/luasrc/usr/lib/lua/gluon/web/model/osm.lua b/package/gluon-web-osm/luasrc/usr/lib/lua/gluon/web/model/osm.lua index ec18a003d6196e9a9410fccdb92f1c2787725794..294caddff77b4427b0d9b5912ae4ce5a57777115 100644 --- a/package/gluon-web-osm/luasrc/usr/lib/lua/gluon/web/model/osm.lua +++ b/package/gluon-web-osm/luasrc/usr/lib/lua/gluon/web/model/osm.lua @@ -4,7 +4,8 @@ local util = require "gluon.web.util" local class = util.class -local DEFAULT_URL = 'https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.2.0' +local DEFAULT_URL = + 'https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@35ffe7626ce16c372143f3c903950750075e7068/en/v5.3.0' local M = {} diff --git a/package/gluon-web/luasrc/usr/lib/lua/gluon/web/dispatcher.lua b/package/gluon-web/luasrc/usr/lib/lua/gluon/web/dispatcher.lua index 2d72777661b2d9a6f565e4836129c7bf3d23ad37..3aca99dcb96428afd26ed73ec73dc214240ce58c 100644 --- a/package/gluon-web/luasrc/usr/lib/lua/gluon/web/dispatcher.lua +++ b/package/gluon-web/luasrc/usr/lib/lua/gluon/web/dispatcher.lua @@ -184,9 +184,15 @@ local function dispatch(config, http, request) return end - http:parse_input(node.filehandler) + local ok, err = pcall(http.parse_input, http, node.filehandler) + if not ok then + http:status(400, "Bad request") + http:prepare_content("text/plain") + http:write(err .. "\r\n") + return + end - local ok, err = pcall(node.target) + ok, err = pcall(node.target) if not ok then http:status(500, "Internal Server Error") renderer.render_layout("error/500", { @@ -208,6 +214,6 @@ return function(config, http) if not ok then http:status(500, "Internal Server Error") http:prepare_content("text/plain") - http:write(err) + http:write(err .. "\r\n") end end diff --git a/package/gluon-web/luasrc/usr/lib/lua/gluon/web/http/protocol.lua b/package/gluon-web/luasrc/usr/lib/lua/gluon/web/http/protocol.lua index 8d070d951d3cd3d48c4a5c38fe1c05a5027227a8..5f56fa1b64b4fcb2fe4e8738cd7e7dc7ec171a87 100644 --- a/package/gluon-web/luasrc/usr/lib/lua/gluon/web/http/protocol.lua +++ b/package/gluon-web/luasrc/usr/lib/lua/gluon/web/http/protocol.lua @@ -108,16 +108,11 @@ end -- o String value containing a chunk of the file data -- o Boolean which indicates whether the current chunk is the last one (eof) local function mimedecode_message_body(src, msg, filecb) - - if msg and msg.env.CONTENT_TYPE then - msg.mime_boundary = msg.env.CONTENT_TYPE:match("^multipart/form%-data; boundary=(.+)$") - end - - if not msg.mime_boundary then - return nil, "Invalid Content-Type found" + local mime_boundary = (msg.env.CONTENT_TYPE or ''):match("^multipart/form%-data; boundary=(.+)$") + if not mime_boundary then + error("Invalid Content-Type found") end - local tlen = 0 local inhdr = false local field = nil @@ -188,10 +183,10 @@ local function mimedecode_message_body(src, msg, filecb) local spos, epos, found repeat - spos, epos = data:find("\r\n--" .. msg.mime_boundary .. "\r\n", 1, true) + spos, epos = data:find("\r\n--" .. mime_boundary .. "\r\n", 1, true) if not spos then - spos, epos = data:find("\r\n--" .. msg.mime_boundary .. "--\r\n", 1, true) + spos, epos = data:find("\r\n--" .. mime_boundary .. "--\r\n", 1, true) end @@ -250,20 +245,61 @@ local function mimedecode_message_body(src, msg, filecb) return true end - return pump(src, snk) + assert(pump(src, snk)) +end + +local function check_post_origin(msg) + local default_port = '80' + local request_scheme = 'http' + if msg.env.HTTPS then + default_port = '443' + request_scheme = 'https' + end + + local request_host = msg.env.HTTP_HOST + if not request_host then + error('POST request without Host header') + end + if not request_host:match(':[0-9]+$') then + request_host = request_host .. ':' .. default_port + end + + local origin = msg.env.HTTP_ORIGIN + if not origin then + error('POST request without Origin header') + end + local origin_scheme, origin_host = origin:match('^([^:]*)://(.*)$') + if not origin_host then + error('POST request with invalid Origin header') + end + if not origin_host:match(':[0-9]+$') then + local origin_port + if origin_scheme == 'http' then + origin_port = '80' + elseif origin_scheme == 'https' then + origin_port = '443' + else + error('POST request with invalid Origin header') + end + origin_host = origin_host .. ':' .. origin_port + end + + if request_scheme ~= origin_scheme or request_host ~= origin_host then + error('Invalid cross-origin POST') + end end -- This function will examine the Content-Type within the given message object -- to select the appropriate content decoder. -- Currently only the multipart/form-data mime type is supported. function M.parse_message_body(src, msg, filecb) - if not (msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE) then + if msg.env.REQUEST_METHOD ~= "POST" then return end - if msg.env.CONTENT_TYPE:match("^multipart/form%-data") then - return mimedecode_message_body(src, msg, filecb) - end + check_post_origin(msg) + + mimedecode_message_body(src, msg, filecb) end return M diff --git a/patches/openwrt/0013-mac80211-create-channel-list-for-fixed-channel-operation.patch b/patches/openwrt/0013-mac80211-create-channel-list-for-fixed-channel-operation.patch index c2178b1eb9e1602600c33b1adc4e45d838854bf8..729a3e573fe761a725f8d80708f05ef15091e329 100644 --- a/patches/openwrt/0013-mac80211-create-channel-list-for-fixed-channel-operation.patch +++ b/patches/openwrt/0013-mac80211-create-channel-list-for-fixed-channel-operation.patch @@ -13,10 +13,10 @@ circumvent this issue. Signed-off-by: David Bauer <mail@david-bauer.net> diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh -index 36aebbb2ccfec2137d5d260fe2111d77f531ddec..367a3e8e37a8e8435c35ca2912ef0855efbdfc78 100644 +index bb48ab9a15e470b6807693e08fdc84fb3c94aeed..272fb2a726bb34fa3ab74dfe48150197dbf918ca 100644 --- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh +++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh -@@ -100,6 +100,9 @@ mac80211_hostapd_setup_base() { +@@ -101,6 +101,9 @@ mac80211_hostapd_setup_base() { json_get_vars noscan ht_coex json_get_values ht_capab_list ht_capab tx_burst diff --git a/patches/openwrt/0015-kernel-bridge-Implement-MLD-Querier-wake-up-calls-Android-bug-workaround.patch b/patches/openwrt/0015-kernel-bridge-Implement-MLD-Querier-wake-up-calls-Android-bug-workaround.patch index ad9cc4f1546dfef308aec986c7fe0c506e57708e..c08c3d2dfebcea281912c61b65fb1f31b7bfa2e4 100644 --- a/patches/openwrt/0015-kernel-bridge-Implement-MLD-Querier-wake-up-calls-Android-bug-workaround.patch +++ b/patches/openwrt/0015-kernel-bridge-Implement-MLD-Querier-wake-up-calls-Android-bug-workaround.patch @@ -1954,10 +1954,10 @@ index 0000000000000000000000000000000000000000..92bb9275df9d54778ce8f00b1cb6e999 +2.27.0 + diff --git a/target/linux/generic/config-4.14 b/target/linux/generic/config-4.14 -index d54ede9efda0a3ffd84e9a0c49dc410a01737d82..15b50523bf55d9a77fc1655ec6ba6ffde6d93a3e 100644 +index cbe2c09af91dcbb036bb71d42b6b1075d7f31012..e7faafd719656769fe2e43ff9145abc28b806827 100644 --- a/target/linux/generic/config-4.14 +++ b/target/linux/generic/config-4.14 -@@ -628,6 +628,7 @@ CONFIG_BRIDGE=y +@@ -629,6 +629,7 @@ CONFIG_BRIDGE=y # CONFIG_BRIDGE_EBT_T_NAT is not set # CONFIG_BRIDGE_EBT_VLAN is not set CONFIG_BRIDGE_IGMP_SNOOPING=y diff --git a/patches/openwrt/0020-ipq40xx-add-support-for-Plasma-Cloud-PA1200.patch b/patches/openwrt/0020-ipq40xx-add-support-for-Plasma-Cloud-PA1200.patch index aec18d5122ba65e671f6f7cd1505447831715a4e..0372f409a2e71859641afe8abfdb436eb28870bd 100644 --- a/patches/openwrt/0020-ipq40xx-add-support-for-Plasma-Cloud-PA1200.patch +++ b/patches/openwrt/0020-ipq40xx-add-support-for-Plasma-Cloud-PA1200.patch @@ -429,7 +429,7 @@ index 0000000000000000000000000000000000000000..bcb9552ce777d1d522c7642649e22ec2 + qcom,ath10k-calibration-variant = "PlasmaCloud-PA1200"; +}; diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile -index 68dcbc59a42f6d8360b87c7b4e74cd34f697b465..e14d00ad08b8caf2dae935d573f0ba7bb0433c23 100644 +index 68dcbc59a42f6d8360b87c7b4e74cd34f697b465..3a2e7a4410afcba1a1369cac328e237fc350668b 100644 --- a/target/linux/ipq40xx/image/Makefile +++ b/target/linux/ipq40xx/image/Makefile @@ -345,6 +345,21 @@ endef @@ -447,7 +447,7 @@ index 68dcbc59a42f6d8360b87c7b4e74cd34f697b465..e14d00ad08b8caf2dae935d573f0ba7b + IMAGES = factory.bin sysupgrade.bin + IMAGE/factory.bin := append-rootfs | pad-rootfs | openmesh-image ce_type=PA1200 + IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-rootfs | sysupgrade-tar rootfs=$$$$@ | append-metadata -+ DEVICE_PACKAGES := uboot-envtools ipq-wifi-plasmacloud-pa1200 ++ DEVICE_PACKAGES := uboot-envtools ipq-wifi-plasmacloud_pa1200 +endef +TARGET_DEVICES += plasmacloud_pa1200 + diff --git a/patches/openwrt/0021-ipq40xx-add-support-for-Plasma-Cloud-PA2200.patch b/patches/openwrt/0021-ipq40xx-add-support-for-Plasma-Cloud-PA2200.patch index b588f083ab8f97c9d9e0e44dfb49fb136cd0aad6..d4f580129411f23f8fe1a4bef624d0e0b586e04d 100644 --- a/patches/openwrt/0021-ipq40xx-add-support-for-Plasma-Cloud-PA2200.patch +++ b/patches/openwrt/0021-ipq40xx-add-support-for-Plasma-Cloud-PA2200.patch @@ -501,7 +501,7 @@ index 0000000000000000000000000000000000000000..2d0655114b4e0749e0c878a3d16ece2a + ieee80211-freq-limit = <5470000 5875000>; +}; diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile -index e14d00ad08b8caf2dae935d573f0ba7bb0433c23..9872d0c4abcbb9d607bb15c47f0f820e7cdea077 100644 +index 3a2e7a4410afcba1a1369cac328e237fc350668b..b6241d622574657b5261a45507ba5959d39eaa67 100644 --- a/target/linux/ipq40xx/image/Makefile +++ b/target/linux/ipq40xx/image/Makefile @@ -360,6 +360,21 @@ define Device/plasmacloud_pa1200 @@ -519,7 +519,7 @@ index e14d00ad08b8caf2dae935d573f0ba7bb0433c23..9872d0c4abcbb9d607bb15c47f0f820e + IMAGES = factory.bin sysupgrade.bin + IMAGE/factory.bin := append-rootfs | pad-rootfs | openmesh-image ce_type=PA2200 + IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-rootfs | sysupgrade-tar rootfs=$$$$@ | append-metadata -+ DEVICE_PACKAGES := ath10k-firmware-qca9888-ct ipq-wifi-plasmacloud-pa2200 uboot-envtools ++ DEVICE_PACKAGES := ath10k-firmware-qca9888-ct ipq-wifi-plasmacloud_pa2200 uboot-envtools +endef +TARGET_DEVICES += plasmacloud_pa2200 + diff --git a/patches/packages/packages/0003-perl-don-t-build-in-parallel-and-bump-release.patch b/patches/packages/packages/0003-perl-don-t-build-in-parallel-and-bump-release.patch new file mode 100644 index 0000000000000000000000000000000000000000..b8fe11d23c4afac4bb7d85ed816a7ab43649d476 --- /dev/null +++ b/patches/packages/packages/0003-perl-don-t-build-in-parallel-and-bump-release.patch @@ -0,0 +1,24 @@ +From: Martin Weinelt <martin@darmstadt.freifunk.net> +Date: Tue, 8 Feb 2022 21:09:20 +0100 +Subject: perl: don't build in parallel and bump release + +Parallel builds cause spurious build failures with high core counts. + +https://github.com/openwrt/packages/issues/8238 +https://github.com/openwrt/packages/pull/17274 + +diff --git a/lang/perl/Makefile b/lang/perl/Makefile +index 84d256d2d8c682f18670a4cbae0a48e3333fb222..c2e5cf8e703af675dd296704597934aa9b5f7446 100644 +--- a/lang/perl/Makefile ++++ b/lang/perl/Makefile +@@ -34,8 +34,8 @@ PKG_BUILD_DIR:=$(BUILD_DIR)/perl/$(PKG_NAME)-$(PKG_VERSION) + HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/perl/$(PKG_NAME)-$(PKG_VERSION) + PKG_INSTALL:=1 + PKG_BUILD_DEPENDS:=perl/host +-PKG_BUILD_PARALLEL:=1 +-HOST_BUILD_PARALLEL:=1 ++PKG_BUILD_PARALLEL:=0 ++HOST_BUILD_PARALLEL:=0 + + # Variables used during configuration/build + HOST_PERL_PREFIX:=$(STAGING_DIR_HOSTPKG)/usr diff --git a/scripts/container.sh b/scripts/container.sh new file mode 100755 index 0000000000000000000000000000000000000000..072d2ec13ba06804faab16c5f4a5ac2b1a4d196d --- /dev/null +++ b/scripts/container.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# move into base directory, in case this script is not executed via `make container` +cd "$(dirname "$0")/.." + +# normalize branch name to reflect a valid image name +BRANCH=$(git branch --show-current 2>/dev/null | sed 's/[^a-z0-9-]/_/ig') +TAG="gluon:${BRANCH:-latest}" + +if [ "$(command -v podman)" ] +then + podman build -t "${TAG}" contrib/docker + podman run -it --rm --userns=keep-id --volume="$(pwd):/gluon" "${TAG}" +elif [ "$(command -v docker)" ] +then + docker build -t "${TAG}" contrib/docker + docker run -it --rm --volume="$(pwd):/gluon" "${TAG}" +else + 1>&2 echo "Please install either podman or docker. Exiting" >/dev/null + exit 1 +fi +