From 86348c815bd23c4a9ecd58586223a222aaac9aad Mon Sep 17 00:00:00 2001 From: ohrensessel Date: Thu, 26 Jun 2014 19:33:31 +0200 Subject: [PATCH] Initial commit gluon-config-mode based on freifunk-gluon/packages@9d364a6fbcb87bc08949ef81e1fbdb6c87f10950 --- gluon-config-mode/Makefile | 38 +++++ .../files/etc/config/gluon-config-mode | 3 + .../etc/hotplug.d/button/50-gluon-config-mode | 29 ++++ .../files/etc/init.d/gluon-config-mode | 90 ++++++++++++ .../files/lib/gluon/config-mode/ash-login | 3 + .../lib/gluon/config-mode/www/cgi-bin/luci | 5 + .../lib/gluon/config-mode/www/index.html | 10 ++ .../lib/gluon/config-mode/www/luci-static | 1 + .../config-mode/invariant/010-config-ifname | 17 +++ .../controller/gluon-config-mode/index.lua | 83 +++++++++++ .../model/cbi/gluon-config-mode/wizard.lua | 139 ++++++++++++++++++ .../lib/lua/luci/tools/gluon-config-mode.lua | 29 ++++ .../view/gluon-config-mode/cbi/wizard.htm | 68 +++++++++ .../luci/view/gluon-config-mode/reboot.htm | 31 ++++ 14 files changed, 546 insertions(+) create mode 100644 gluon-config-mode/Makefile create mode 100644 gluon-config-mode/files/etc/config/gluon-config-mode create mode 100755 gluon-config-mode/files/etc/hotplug.d/button/50-gluon-config-mode create mode 100755 gluon-config-mode/files/etc/init.d/gluon-config-mode create mode 100755 gluon-config-mode/files/lib/gluon/config-mode/ash-login create mode 100755 gluon-config-mode/files/lib/gluon/config-mode/www/cgi-bin/luci create mode 100644 gluon-config-mode/files/lib/gluon/config-mode/www/index.html create mode 120000 gluon-config-mode/files/lib/gluon/config-mode/www/luci-static create mode 100755 gluon-config-mode/files/lib/gluon/upgrade/config-mode/invariant/010-config-ifname create mode 100644 gluon-config-mode/files/usr/lib/lua/luci/controller/gluon-config-mode/index.lua create mode 100644 gluon-config-mode/files/usr/lib/lua/luci/model/cbi/gluon-config-mode/wizard.lua create mode 100644 gluon-config-mode/files/usr/lib/lua/luci/tools/gluon-config-mode.lua create mode 100644 gluon-config-mode/files/usr/lib/lua/luci/view/gluon-config-mode/cbi/wizard.htm create mode 100644 gluon-config-mode/files/usr/lib/lua/luci/view/gluon-config-mode/reboot.htm diff --git a/gluon-config-mode/Makefile b/gluon-config-mode/Makefile new file mode 100644 index 0000000..9a28d02 --- /dev/null +++ b/gluon-config-mode/Makefile @@ -0,0 +1,38 @@ +# Copyright (C) 2012 Nils Schneider +# This is free software, licensed under the Apache 2.0 license. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-config-mode +PKG_VERSION:=2 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-config-mode + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Luci based config mode for user friendly setup of new meshnodes + DEPENDS:=+gluon-luci-core +gluon-lock-password +gluon-node-info +gluon-simple-tc +uhttpd +dnsmasq +ip +endef + +define Package/gluon-config-mode/description + Luci based config mode +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-config-mode/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-config-mode)) diff --git a/gluon-config-mode/files/etc/config/gluon-config-mode b/gluon-config-mode/files/etc/config/gluon-config-mode new file mode 100644 index 0000000..c2d2be2 --- /dev/null +++ b/gluon-config-mode/files/etc/config/gluon-config-mode @@ -0,0 +1,3 @@ +config wizard + option enabled '0' + option configured '0' diff --git a/gluon-config-mode/files/etc/hotplug.d/button/50-gluon-config-mode b/gluon-config-mode/files/etc/hotplug.d/button/50-gluon-config-mode new file mode 100755 index 0000000..7648cd6 --- /dev/null +++ b/gluon-config-mode/files/etc/hotplug.d/button/50-gluon-config-mode @@ -0,0 +1,29 @@ +#!/bin/sh + + +wait=3 + + +wait_config_mode() { + sleep $wait + uci set 'gluon-config-mode.@wizard[0].enabled=1' + uci commit gluon-config-mode + reboot +} + + +if [ "$BUTTON" = wps -o "$BUTTON" = reset ]; then + case "$ACTION" in + pressed) + wait_config_mode & + PID=$! + echo $PID > /tmp/.wait_config_mode + ;; + released) + if [ -r /tmp/.wait_config_mode ]; then + kill $(cat /tmp/.wait_config_mode) + rm /tmp/.wait_config_mode + fi + ;; + esac +fi diff --git a/gluon-config-mode/files/etc/init.d/gluon-config-mode b/gluon-config-mode/files/etc/init.d/gluon-config-mode new file mode 100755 index 0000000..e613f7b --- /dev/null +++ b/gluon-config-mode/files/etc/init.d/gluon-config-mode @@ -0,0 +1,90 @@ +#!/bin/sh /etc/rc.common + +START=12 + + +CONFIG_MODE_ADDR=192.168.1.1 +CONFIG_MODE_NETMASK=255.255.255.0 + +CONFIG_MODE_DHCP_RANGE=192.168.1.2,192.168.1.254 + + +delete_interface() { + [ "$1" = 'loopback' ] || uci_remove network "$1" +} + + +check_enable() { + config_get enabled "$1" enabled + config_get configured "$1" configured + + if [ "$enabled" = 1 -o "$configured" != 1 ]; then + export enable=1 + fi +} + +setup_network() { + ( + export UCI_CONFIG_DIR=/var/gluon/config-mode/config + + mkdir -p "$UCI_CONFIG_DIR" + + cp /etc/config/network "$UCI_CONFIG_DIR" + + config_load network + config_foreach delete_interface interface + + uci_add network interface config + uci_set network config ifname "$(sysconfig config_ifname)" + uci_set network config type 'bridge' + uci_set network config proto 'static' + uci_set network config ipaddr "$CONFIG_MODE_ADDR" + uci_set network config netmask "$CONFIG_MODE_NETMASK" + + uci_commit network + + SERVICE_DAEMONIZE=1 + SERVICE_WRITE_PID=1 + service_start /sbin/netifd -c "$UCI_CONFIG_DIR" + + setup_switch() { return 0; } + + include /lib/network + setup_switch + ) +} + +start() { + . /lib/gluon/functions/sysconfig.sh + + enable=0 + config_load gluon-config-mode + config_foreach check_enable wizard + + if [ "$enable" = '1' ]; then + lua -luci -e 'require "luci.model.uci"; uci_state=luci.model.uci.cursor_state(); uci_state:section("gluon-config-mode", "wizard", nil, { running = "1" }); uci_state:save("gluon-config-mode")' + uci set 'gluon-config-mode.@wizard[0].enabled=0' + uci commit gluon-config-mode + + setup_network + + /usr/sbin/telnetd -l /lib/gluon/config-mode/ash-login + /etc/init.d/dropbear start + + /usr/sbin/uhttpd -h /lib/gluon/config-mode/www -x /cgi-bin -A 1 -R -p 0.0.0.0:80 + + /usr/sbin/dnsmasq -p 0 -F $CONFIG_MODE_DHCP_RANGE -l /tmp/dhcp.leases -O option:router + + /etc/init.d/led start + + # correctly finish firstboot + /etc/init.d/done boot + + . /etc/diag.sh + get_status_led + status_led_set_timer 1000 300 + + # block further boot + while true; do sleep 1; done + fi +} diff --git a/gluon-config-mode/files/lib/gluon/config-mode/ash-login b/gluon-config-mode/files/lib/gluon/config-mode/ash-login new file mode 100755 index 0000000..3349c44 --- /dev/null +++ b/gluon-config-mode/files/lib/gluon/config-mode/ash-login @@ -0,0 +1,3 @@ +#!/bin/sh + +exec /bin/ash --login diff --git a/gluon-config-mode/files/lib/gluon/config-mode/www/cgi-bin/luci b/gluon-config-mode/files/lib/gluon/config-mode/www/cgi-bin/luci new file mode 100755 index 0000000..c5c9847 --- /dev/null +++ b/gluon-config-mode/files/lib/gluon/config-mode/www/cgi-bin/luci @@ -0,0 +1,5 @@ +#!/usr/bin/lua +require "luci.cacheloader" +require "luci.sgi.cgi" +luci.dispatcher.indexcache = "/tmp/luci-indexcache" +luci.sgi.cgi.run() diff --git a/gluon-config-mode/files/lib/gluon/config-mode/www/index.html b/gluon-config-mode/files/lib/gluon/config-mode/www/index.html new file mode 100644 index 0000000..0a7238b --- /dev/null +++ b/gluon-config-mode/files/lib/gluon/config-mode/www/index.html @@ -0,0 +1,10 @@ + + + + + + + +LuCI - Lua Configuration Interface + + diff --git a/gluon-config-mode/files/lib/gluon/config-mode/www/luci-static b/gluon-config-mode/files/lib/gluon/config-mode/www/luci-static new file mode 120000 index 0000000..aea80e0 --- /dev/null +++ b/gluon-config-mode/files/lib/gluon/config-mode/www/luci-static @@ -0,0 +1 @@ +/www/luci-static \ No newline at end of file diff --git a/gluon-config-mode/files/lib/gluon/upgrade/config-mode/invariant/010-config-ifname b/gluon-config-mode/files/lib/gluon/upgrade/config-mode/invariant/010-config-ifname new file mode 100755 index 0000000..ce54a9b --- /dev/null +++ b/gluon-config-mode/files/lib/gluon/upgrade/config-mode/invariant/010-config-ifname @@ -0,0 +1,17 @@ +#!/bin/sh + +. /lib/gluon/functions/sysconfig.sh +. /lib/ar71xx.sh + + +sysconfig_isset config_ifname && exit 0 + + +case "$(ar71xx_board_name)" in + nanostation-m) + sysconfig_set config_ifname "$(sysconfig wan_ifname || sysconfig lan_ifname)" + ;; + *) + sysconfig_set config_ifname "$(sysconfig lan_ifname || sysconfig wan_ifname)" + ;; +esac diff --git a/gluon-config-mode/files/usr/lib/lua/luci/controller/gluon-config-mode/index.lua b/gluon-config-mode/files/usr/lib/lua/luci/controller/gluon-config-mode/index.lua new file mode 100644 index 0000000..d8b21b8 --- /dev/null +++ b/gluon-config-mode/files/usr/lib/lua/luci/controller/gluon-config-mode/index.lua @@ -0,0 +1,83 @@ +--[[ +Copyright 2013 Nils Schneider + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.gluon-config-mode.index", package.seeall) + +local site = require 'gluon.site_config' + + +local meshvpn_name = "mesh_vpn" + + +function index() + local uci_state = luci.model.uci.cursor_state() + + if uci_state:get_first("gluon-config-mode", "wizard", "running", "0") == "1" then + local root = node() + if not root.target then + root.target = alias("gluon-config-mode") + root.index = true + end + + page = node() + page.lock = true + page.target = alias("gluon-config-mode") + page.subindex = true + page.index = false + + page = node("gluon-config-mode") + page.title = _("Wizard") + page.target = alias("gluon-config-mode", "wizard") + page.order = 5 + page.setuser = "root" + page.setgroup = "root" + page.index = true + + entry({"gluon-config-mode", "wizard"}, form("gluon-config-mode/wizard")).index = true + entry({"gluon-config-mode", "reboot"}, call("action_reboot")) + end +end + +function action_reboot() + local configmode = require "luci.tools.gluon-config-mode" + local pubkey + local uci = luci.model.uci.cursor() + local meshvpn_enabled = uci:get("fastd", meshvpn_name, "enabled", "0") + local sysconfig = require 'gluon.sysconfig' + if meshvpn_enabled == "1" then + pubkey = configmode.get_fastd_pubkey(meshvpn_name) + end + + uci:set("gluon-config-mode", uci:get_first("gluon-config-mode", "wizard"), "configured", "1") + uci:save("gluon-config-mode") + uci:commit("gluon-config-mode") + + local hostname = uci:get_first("system", "system", "hostname") + + if nixio.fork() ~= 0 then + luci.template.render("gluon-config-mode/reboot", + {luci=luci, pubkey=pubkey, hostname=hostname, site=site, sysconfig=sysconfig}) + else + debug.setfenv(io.stdout, debug.getfenv(io.open '/dev/null')) + io.stdout:close() + + -- Sleep a little so the browser can fetch everything required to + -- display the reboot page, then reboot the device. + nixio.nanosleep(2) + + -- Run reboot with popen so it gets its own std filehandles. + io.popen("reboot") + + -- Prevent any further execution in this child. + os.exit() + end +end diff --git a/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/gluon-config-mode/wizard.lua b/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/gluon-config-mode/wizard.lua new file mode 100644 index 0000000..a069832 --- /dev/null +++ b/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/gluon-config-mode/wizard.lua @@ -0,0 +1,139 @@ +local configmode = require "luci.tools.gluon-config-mode" +local meshvpn_name = "mesh_vpn" +local uci = luci.model.uci.cursor() +local f, s, o + +-- prepare fastd key as early as possible +configmode.setup_fastd_secret(meshvpn_name) + +f = SimpleForm("wizard") +f.reset = false +f.template = "gluon-config-mode/cbi/wizard" +f.submit = "Fertig" + +s = f:section(SimpleSection, nil, nil) + +o = s:option(Value, "_hostname", "Name dieses Knotens") +o.value = uci:get_first("system", "system", "hostname") +o.rmempty = false +o.datatype = "hostname" + +o = s:option(Flag, "_autoupdate", "Firmware automatisch aktualisieren") +o.default = uci:get_bool("autoupdater", "settings", "enabled") and o.enabled or o.disabled +o.rmempty = false + +s = f:section(SimpleSection, nil, [[Falls du deinen Knoten über das Internet +mit Freifunk verbinden möchtest, kannst du hier das Mesh-VPN aktivieren. +Solltest du dich dafür entscheiden, hast du die Möglichkeit die dafür +genutzte Bandbreite zu beschränken.]]) + +o = s:option(Flag, "_meshvpn", "Mesh-VPN aktivieren") +o.default = uci:get_bool("fastd", meshvpn_name, "enabled") and o.enabled or o.disabled +o.rmempty = false + +o = s:option(Flag, "_limit_enabled", "Mesh-VPN Bandbreite begrenzen") +o:depends("_meshvpn", "1") +o.default = uci:get_bool("gluon-simple-tc", meshvpn_name, "enabled") and o.enabled or o.disabled +o.rmempty = false + +o = s:option(Value, "_limit_ingress", "Downstream (kbit/s)") +o:depends("_limit_enabled", "1") +o.value = uci:get("gluon-simple-tc", meshvpn_name, "limit_ingress") +o.rmempty = false +o.datatype = "integer" + +o = s:option(Value, "_limit_egress", "Upstream (kbit/s)") +o:depends("_limit_enabled", "1") +o.value = uci:get("gluon-simple-tc", meshvpn_name, "limit_egress") +o.rmempty = false +o.datatype = "integer" + +s = f:section(SimpleSection, nil, [[Um deinen Knoten auf der Karte anzeigen +zu können, benötigen wir seine Koordinaten. Hier hast du die Möglichkeit, +diese zu hinterlegen.]]) + +o = s:option(Flag, "_location", "Knoten auf der Karte anzeigen") +o.default = uci:get_first("gluon-node-info", "location", "share_location", o.disabled) +o.rmempty = false + +o = s:option(Value, "_latitude", "Breitengrad") +o.default = uci:get_first("gluon-node-info", "location", "latitude") +o:depends("_location", "1") +o.rmempty = false +o.datatype = "float" +o.description = "z.B. 53.873621" + +o = s:option(Value, "_longitude", "Längengrad") +o.default = uci:get_first("gluon-node-info", "location", "longitude") +o:depends("_location", "1") +o.rmempty = false +o.datatype = "float" +o.description = "z.B. 10.689901" + +s = f:section(SimpleSection, nil, [[Hier kannst du einen +öffentlichen Hinweis hinterlegen um anderen Freifunkern zu +ermöglichen Kontakt mit dir aufzunehmen. Bitte beachte, dass dieser Hinweis +auch öffentlich im Internet, zusammen mit den Koordinaten deines Knotens, +einsehbar sein wird.]]) + +o = s:option(Value, "_contact", "Kontakt") +o.default = uci:get_first("gluon-node-info", "owner", "contact", "") +o.rmempty = true +o.datatype = "string" +o.description = "z.B. E-Mail oder Telefonnummer" +o.maxlen = 140 + +function f.handle(self, state, data) + if state == FORM_VALID then + local stat = false + + uci:set("autoupdater", "settings", "enabled", data._autoupdate) + uci:save("autoupdater") + uci:commit("autoupdater") + + -- checks for nil needed due to o:depends(...) + if data._limit_enabled ~= nil then + uci:set("gluon-simple-tc", meshvpn_name, "interface") + uci:set("gluon-simple-tc", meshvpn_name, "enabled", data._limit_enabled) + uci:set("gluon-simple-tc", meshvpn_name, "ifname", "mesh-vpn") + + if data._limit_ingress ~= nil then + uci:set("gluon-simple-tc", meshvpn_name, "limit_ingress", data._limit_ingress) + end + + if data._limit_egress ~= nil then + uci:set("gluon-simple-tc", meshvpn_name, "limit_egress", data._limit_egress) + end + + uci:commit("gluon-simple-tc") + end + + uci:set("fastd", meshvpn_name, "enabled", data._meshvpn) + uci:save("fastd") + uci:commit("fastd") + + uci:set("system", uci:get_first("system", "system"), "hostname", data._hostname) + uci:save("system") + uci:commit("system") + + local sname = uci:get_first("gluon-node-info", "location") + uci:set("gluon-node-info", sname, "share_location", data._location) + if data._location and data._latitude ~= nil and data._longitude ~= nil then + uci:set("gluon-node-info", sname, "latitude", data._latitude) + uci:set("gluon-node-info", sname, "longitude", data._longitude) + end + if data._contact ~= nil then + uci:set("gluon-node-info", uci:get_first("gluon-node-info", "owner"), "contact", data._contact) + else + uci:delete("gluon-node-info", uci:get_first("gluon-node-info", "owner"), "contact") + end + uci:save("gluon-node-info") + uci:commit("gluon-node-info") + + luci.http.redirect(luci.dispatcher.build_url("gluon-config-mode", "reboot")) + end + + return true +end + +return f diff --git a/gluon-config-mode/files/usr/lib/lua/luci/tools/gluon-config-mode.lua b/gluon-config-mode/files/usr/lib/lua/luci/tools/gluon-config-mode.lua new file mode 100644 index 0000000..ba1748f --- /dev/null +++ b/gluon-config-mode/files/usr/lib/lua/luci/tools/gluon-config-mode.lua @@ -0,0 +1,29 @@ +local luci = require "luci" +local io = require "io" + +module "luci.tools.gluon-config-mode" + +function setup_fastd_secret(name) + local uci = luci.model.uci.cursor() + local secret = uci:get("fastd", name, "secret") + + if not secret or not secret:match("%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x") then + local f = io.popen("fastd --generate-key --machine-readable", "r") + local secret = f:read("*a") + f:close() + + uci:set("fastd", name, "secret", secret) + uci:save("fastd") + uci:commit("fastd") + end +end + +function get_fastd_pubkey(name) + local f = io.popen("/etc/init.d/fastd show_key " .. name, "r") + local key = f:read("*a") + f:close() + + return key +end + + diff --git a/gluon-config-mode/files/usr/lib/lua/luci/view/gluon-config-mode/cbi/wizard.htm b/gluon-config-mode/files/usr/lib/lua/luci/view/gluon-config-mode/cbi/wizard.htm new file mode 100644 index 0000000..cadfb00 --- /dev/null +++ b/gluon-config-mode/files/usr/lib/lua/luci/view/gluon-config-mode/cbi/wizard.htm @@ -0,0 +1,68 @@ +<%- + local site = require 'gluon.site_config' + local sysconfig = require 'gluon.sysconfig' + local template = require 'luci.template' +-%> + +

Willkommen!

+

+ <%= template.render_string(site.config_mode.msg_welcome, {hostname=hostname, sysconfig=sysconfig}) %> +

+ +<% if not self.embedded then %> +
+
+ + +
+<% end %> +
+ <% if self.title and #self.title > 0 then %>

<%=self.title%>

<% end %> + <% if self.description and #self.description > 0 then %>
<%=self.description%>
<% end %> + <% self:render_children() %> +
+
+<%- if self.message then %> +
<%=self.message%>
+<%- end %> +<%- if self.errmessage then %> +
<%=self.errmessage%>
+<%- end %> +<% if not self.embedded then %> +
+<%- + if type(self.hidden) == "table" then + for k, v in pairs(self.hidden) do +-%> + +<%- + end + end +%> +<% if redirect then %> +
+ +
+<% end %> +<%- if self.flow and self.flow.skip then %> + +<% end %> +<%- if self.submit ~= false then %> + +<% end %> +<%- if self.reset ~= false then %> + +<% end %> +<%- if self.cancel ~= false and self.on_cancel then %> + +<% end %> + +
+
+<% end %> diff --git a/gluon-config-mode/files/usr/lib/lua/luci/view/gluon-config-mode/reboot.htm b/gluon-config-mode/files/usr/lib/lua/luci/view/gluon-config-mode/reboot.htm new file mode 100644 index 0000000..db9cbc2 --- /dev/null +++ b/gluon-config-mode/files/usr/lib/lua/luci/view/gluon-config-mode/reboot.htm @@ -0,0 +1,31 @@ + + + + + + <%=hostname%> - <% if title then %><%=title%><% else %><%:Rebooting...%><% end %> + + + +
+
+

Geschafft! Dein Freifunkknoten ist nun fertig eingerichtet.

+ <% if pubkey then %> +
+

+ <%= luci.template.render_string(site.config_mode.msg_pubkey) %> +

+
+ # <%= hostname %> +
+ <%= pubkey %> +
+
+ <% end %> +
+ <%= luci.template.render_string(site.config_mode.msg_reboot) %> +
+
+
+ +