Ejemplo n.º 1
0
    def get_page_form(
        self, form_name: str, data: dict, controller_id: str
    ) -> typing.Tuple[fapi.ForisAjaxForm, typing.Callable[[dict], typing.Tuple[
            "str", "str"]]]:
        """Returns appropriate foris form and handler to generate response
        """
        form: fapi.ForisAjaxForm
        if form_name == "sub-form":
            form = handlers.SubordinatesEditForm(data)

            def prepare_message(results: dict) -> dict:
                if results["result"]:
                    message = {
                        "classes": ["success"],
                        "text":
                        _("Device '%(controller_id)s' was successfully updated."
                          ) % dict(controller_id=data["controller_id"]),
                    }

                else:
                    message = {
                        "classes": ["error"],
                        "text":
                        _("Failed to update subordinate '%(controller_id)s'.")
                        % dict(controller_id=data["controller_id"]),
                    }
                return message

            form.url = reverse("config_ajax_form",
                               page_name="subordinates-setup",
                               form_name="sub-form")
            return form, prepare_message

        elif form_name == "subsub-form":
            form = handlers.SubsubordinatesEditForm(data)

            def prepare_message(results: dict) -> dict:
                if results["result"]:
                    message = {
                        "classes": ["success"],
                        "text":
                        _("Subsubordinate '%(controller_id)s' was successfully updated."
                          ) % dict(controller_id=data["controller_id"]),
                    }

                else:
                    message = {
                        "classes": ["error"],
                        "text":
                        _("Failed to update subsubordinate '%(controller_id)s'."
                          ) % dict(controller_id=data["controller_id"]),
                    }
                return message

            form.url = reverse("config_ajax_form",
                               page_name="subordinates-setup",
                               form_name="subsub-form")
            return form, prepare_message

        raise bottle.HTTPError(404, "No form '%s' not found." % form_name)
Ejemplo n.º 2
0
    def _action_check_registration(self):
        handler = RegistrationCheckHandler(bottle.request.POST.decode())
        if not handler.save():
            messages.warning(_("There were some errors in your input."))
            return self.render(registration_check_form=handler.form)

        email = handler.data["email"]

        result = handler.form.callback_results
        kwargs = {}
        if not result["success"]:
            messages.error(
                _("An error ocurred when checking the registration: "
                  "<br><pre>%(error)s</pre>" % dict(error=result["error"])))
            return self.render()
        else:
            if result["status"] == "owned":
                messages.success(
                    _("Registration for the entered email is valid. "
                      "Now you can enable the data collection."))
                collection_toggle_handler = CollectionToggleHandler(
                    bottle.request.POST.decode())
                kwargs[
                    'collection_toggle_form'] = collection_toggle_handler.form
            elif result["status"] == "foreign":
                messages.warning(
                    _('This router is currently assigned to a different email address. Please '
                      'continue to the <a href="%(url)s">Turris website</a> and use the '
                      'registration code <strong>%(reg_num)s</strong> for a re-assignment to your '
                      'email address.') %
                    dict(url=result["url"],
                         reg_num=result["registration_number"]))
                bottle.redirect(
                    reverse("config_page", page_name="data_collect") + "?" +
                    urlencode({"email": email}))
            elif result["status"] == "free":
                messages.info(
                    _('This email address is not registered yet. Please continue to the '
                      '<a href="%(url)s">Turris website</a> and use the registration code '
                      '<strong>%(reg_num)s</strong> to create a new account.')
                    % dict(url=result["url"],
                           reg_num=result["registration_number"]))
                bottle.redirect(
                    reverse("config_page", page_name="data_collect") + "?" +
                    urlencode({"email": email}))
            elif result["status"] == "not_found":
                messages.error(
                    _('Router failed to authorize. Please try to validate our email later.'
                      ))
                bottle.redirect(
                    reverse("config_page", page_name="data_collect") + "?" +
                    urlencode({"email": email}))
        return self.render(status=result["status"],
                           registration_url=result["url"],
                           reg_num=result["registration_number"],
                           **kwargs)
Ejemplo n.º 3
0
 def _action_save_notifications(self):
     if bottle.request.method != "POST":
         messages.error(_("Wrong HTTP method."))
         bottle.redirect(reverse("config_page", page_name="maintenance"))
     handler = notifications.NotificationsHandler(bottle.request.POST.decode())
     if handler.save():
         messages.success(_("Configuration was successfully saved."))
         bottle.redirect(reverse("config_page", page_name="maintenance"))
     messages.warning(_("There were some errors in your input."))
     return super(MaintenanceConfigPage, self).render(notifications_form=handler.form)
Ejemplo n.º 4
0
 def _action_save_notifications(self):
     if bottle.request.method != 'POST':
         messages.error(_("Wrong HTTP method."))
         bottle.redirect(reverse("config_page", page_name="maintenance"))
     handler = notifications.NotificationsHandler(request.POST.decode())
     if handler.save():
         messages.success(_("Configuration was successfully saved."))
         bottle.redirect(reverse("config_page", page_name="maintenance"))
     messages.warning(_("There were some errors in your input."))
     return super(MaintenanceConfigPage, self).render(notifications_form=handler.form)
Ejemplo n.º 5
0
    def _action_toggle_collecting(self):
        if bottle.request.method != 'POST':
            messages.error(_("Wrong HTTP method."))
            bottle.redirect(reverse("config_page", page_name="data_collect"))

        handler = CollectionToggleHandler(bottle.request.POST.decode())
        if handler.save():
            messages.success(_("Configuration was successfully saved."))
            bottle.redirect(reverse("config_page", page_name="data_collect"))

        messages.warning(_("There were some errors in your input."))
        return super().render(collection_toggle_form=handler.form)
Ejemplo n.º 6
0
Archivo: wifi.py Proyecto: CZ-NIC/foris
    def _action_reset(self):

        if bottle.request.method != "POST":
            messages.error(_("Wrong HTTP method."))
            bottle.redirect(reverse("config_page", page_name="wifi"))

        data = current_state.backend.perform("wifi", "reset")
        if "result" in data and data["result"] is True:
            messages.success(_("Wi-Fi reset was successful."))
        else:
            messages.error(_("Failed to perform Wi-Fi reset."))

        bottle.redirect(reverse("config_page", page_name="wifi"))
Ejemplo n.º 7
0
    def _action_reset(self):

        if bottle.request.method != "POST":
            messages.error(_("Wrong HTTP method."))
            bottle.redirect(reverse("config_page", page_name="wifi"))

        data = current_state.backend.perform("wifi", "reset")
        if "result" in data and data["result"] is True:
            messages.success(_("Wi-Fi reset was successful."))
        else:
            messages.error(_("Failed to perform Wi-Fi reset."))

        bottle.redirect(reverse("config_page", page_name="wifi"))
Ejemplo n.º 8
0
def ping():
    res = bottle.response.copy(cls=bottle.HTTPResponse)
    res.content_type = 'application/json'

    next = bottle.request.GET.get('next', None)
    login_url = "%s://%s" % (bottle.request.urlparts.scheme, bottle.request.urlparts.netloc)
    login_url = "%s%s?next=%s" % (login_url, reverse("login"), next) if next else \
        "%s%s" % (login_url, reverse("login"))
    res.body = json.dumps(dict(msg="pong", loginUrl=login_url))
    res.status = 200
    res.set_header('Access-Control-Allow-Origin', '*')
    res.set_header('Access-Control-Allow-Methods', 'GET, OPTIONS')
    res.set_header('Access-Control-Allow-Headers', 'Origin, Accept, Content-Type, X-Requested-With')
    raise res
Ejemplo n.º 9
0
def config_action_post(page_name, action):
    bottle.SimpleTemplate.defaults["active_config_page_key"] = page_name
    bottle.Jinja2Template.defaults["active_config_page_key"] = page_name
    ConfigPage = get_config_page(page_name)
    config_page = ConfigPage(request.POST.decode())
    if request.is_xhr:
        if request.POST.pop("_update", None):
            # if update was requested, just render the page - otherwise handle actions as usual
            return config_page.render(is_xhr=True)
    # check if the button click wasn't any sub-action
    subaction = request.POST.pop("action", None)
    if subaction:
        return config_action_post(page_name, subaction)
    try:
        result = config_page.call_action(action)
        try:
            if not result:
                bottle.redirect(reverse("config_page", page_name=page_name))
        except TypeError:
            # raised by Validator - could happen when the form is posted with wrong fields
            messages.error(_("Configuration could not be saved due to an internal error."))
            logger.exception("Error when saving form.")
        logger.warning("Form not saved.")
        return result
    except ValueError:
        raise bottle.HTTPError(404, "Unknown action.")
Ejemplo n.º 10
0
def config_action_post(page_name, action):
    bottle.SimpleTemplate.defaults["active_config_page_key"] = page_name
    bottle.Jinja2Template.defaults["active_config_page_key"] = page_name
    ConfigPage = get_config_page(page_name)
    config_page = ConfigPage(request.POST.decode())
    if request.is_xhr:
        if request.POST.pop("_update", None):
            # if update was requested, just render the page - otherwise handle actions as usual
            return config_page.render(is_xhr=True)
    # check if the button click wasn't any sub-action
    subaction = request.POST.pop("action", None)
    if subaction:
        return config_action_post(page_name, subaction)
    try:
        result = config_page.call_action(action)
        try:
            if not result:
                bottle.redirect(reverse("config_page", page_name=page_name))
        except TypeError:
            # raised by Validator - could happen when the form is posted with wrong fields
            messages.error(
                _("Configuration could not be saved due to an internal error.")
            )
            logger.exception("Error when saving form.")
        logger.warning("Form not saved.")
        return result
    except ValueError:
        raise bottle.HTTPError(404, "Unknown action.")
Ejemplo n.º 11
0
    def _ajax_prepare_token(self):
        self._check_post()
        RemoteConfigPage.token_cleanup()

        form = self.get_token_id_form(bottle.request.POST.decode())
        token_id = form.data.get("token_id")
        if not token_id:
            raise bottle.HTTPError(404, "id not found")
        name = form.data.get("name", token_id)

        res = current_state.backend.perform("remote", "get_token",
                                            {"id": form.data["token_id"]})
        if res["status"] != "valid":
            raise bottle.HTTPError(404, "token not found")

        bottle.response.set_header("Content-Type", "application/json")
        new_uuid = uuid.uuid4()
        RemoteConfigPage.token_links[str(new_uuid)] = {
            "expiration": time.time() + RemoteConfigPage.TOKEN_LINK_EXPIRATION,
            "name": name,
            "token": base64.b64decode(res["token"]),
        }

        return {
            "url":
            reverse("config_insecure",
                    page_name="remote",
                    identifier=str(new_uuid)),
            "expires_in":
            RemoteConfigPage.TOKEN_LINK_EXPIRATION,
        }
Ejemplo n.º 12
0
def logout():
    session = bottle.request.environ["foris.session"]

    if "user_authenticated" in session:
        session.load_anonymous()

    bottle.redirect(reverse("index"))
Ejemplo n.º 13
0
    def get_page_form(
        self, form_name: str, data: dict, controller_id: str
    ) -> typing.Tuple[fapi.ForisAjaxForm, typing.Callable[[dict], typing.Tuple[
            "str", "str"]]]:
        """Returns appropriate foris form and handler to generate response
        """
        if form_name == "wifi-form":
            form = handlers.SubordinatesWifiEditForm(
                data, controller_id=controller_id, enable_guest=False)

            def prepare_message(results: dict) -> dict:
                if results["result"]:
                    message = {
                        "classes": ["success"],
                        "text": _("Wi-Fi settings were successfully updated."),
                    }

                else:
                    message = {
                        "classes": ["error"],
                        "text": _("Failed to update Wi-Fi settings.")
                    }
                return message

            form.url = reverse("config_ajax_form",
                               page_name="subordinates-wifi",
                               form_name="wifi-form")
            return form, prepare_message

        raise bottle.HTTPError(404, "No form '%s' not found." % form_name)
Ejemplo n.º 14
0
def logout():
    session = bottle.request.environ["foris.session"]

    if "user_authenticated" in session:
        session.load_anonymous()

    bottle.redirect(reverse("index"))
Ejemplo n.º 15
0
 def _action_delete_ca(self):
     self._check_post()
     data = current_state.backend.perform("remote", "delete_ca")
     if data["result"]:
         messages.success(_("CA for remote access was sucessfully deleted."))
     else:
         messages.error(_("Failed to delete CA for remote access."))
     bottle.redirect(reverse("config_page", page_name="remote"))
Ejemplo n.º 16
0
def _redirect_to_default_location():

    next_page = "notifications"
    # by default redirect to current guide step
    if current_state.guide.enabled:
        next_page = current_state.guide.current if current_state.guide.current else next_page

    bottle.redirect(reverse("config_page", page_name=next_page))
Ejemplo n.º 17
0
def ping():
    res = bottle.response.copy(cls=bottle.HTTPResponse)
    res.content_type = "application/json"

    next = bottle.request.GET.get("next", None)
    login_url = "%s://%s" % (bottle.request.urlparts.scheme, bottle.request.urlparts.netloc)
    login_url = (
        "%s%s?next=%s" % (login_url, reverse("login"), next)
        if next
        else "%s%s" % (login_url, reverse("login"))
    )
    res.body = json.dumps(dict(msg="pong", loginUrl=login_url))
    res.status = 200
    res.set_header("Access-Control-Allow-Origin", "*")
    res.set_header("Access-Control-Allow-Methods", "GET, OPTIONS")
    res.set_header("Access-Control-Allow-Headers", "Origin, Accept, Content-Type, X-Requested-With")
    raise res
Ejemplo n.º 18
0
def _redirect_to_default_location():

    next_page = "notifications"
    # by default redirect to current guide step
    if current_state.guide.enabled:
        next_page = current_state.guide.current if current_state.guide.current else next_page

    bottle.redirect(reverse("config_page", page_name=next_page))
Ejemplo n.º 19
0
    def _check_and_get_controller_id(self):
        if bottle.request.method != "POST":
            messages.error(_("Wrong HTTP method."))
            bottle.redirect(reverse("config_page", page_name="remote"))

        form = self.get_controller_id_form(bottle.request.POST.decode())
        if not form.data["controller_id"]:
            raise bottle.HTTPError(404, "controller_id not found")
        return form.data["controller_id"]
Ejemplo n.º 20
0
    def _action_test_notifications(self):
        if bottle.request.method != 'POST':
            messages.error(_("Wrong HTTP method."))
            bottle.redirect(reverse("config_page", page_name="maintenance"))
        data = current_state.backend.perform(
            "router_notifications", "create",
            {
                "msg": "_(This is a testing notification. Please ignore me.)",
                "severity": "news",
                "immediate": True,
            }
        )

        if data["result"]:
            messages.success(_("Testing message was sent, please check your inbox."))
        else:
            messages.error(_(
                "Sending of the testing message failed, your configuration is possibly wrong."
            ))
        bottle.redirect(reverse("config_page", page_name="maintenance"))
Ejemplo n.º 21
0
def reboot():
    data = current_state.backend.perform("maintain", "reboot")

    if bottle.request.is_xhr:
        # return a list of ip addresses where to connect after reboot is performed
        res = bottle.response.copy(cls=bottle.HTTPResponse)
        res.content_type = 'application/json'
        res.body = json.dumps(data)
        res.status = 200
        raise res
    else:
        bottle.redirect(reverse("/"))
Ejemplo n.º 22
0
    def _action_test_notifications(self):
        if bottle.request.method != "POST":
            messages.error(_("Wrong HTTP method."))
            bottle.redirect(reverse("config_page", page_name="maintenance"))
        data = current_state.backend.perform(
            "router_notifications",
            "create",
            {
                "msg": "_(This is a testing notification. Please ignore me.)",
                "severity": "news",
                "immediate": True,
            },
        )

        if data["result"]:
            messages.success(_("Testing message was sent, please check your inbox."))
        else:
            messages.error(
                _("Sending of the testing message failed, your configuration is possibly wrong.")
            )
        bottle.redirect(reverse("config_page", page_name="maintenance"))
Ejemplo n.º 23
0
def reboot():
    data = current_state.backend.perform("maintain", "reboot")

    if bottle.request.is_xhr:
        # return a list of ip addresses where to connect after reboot is performed
        res = bottle.response.copy(cls=bottle.HTTPResponse)
        res.content_type = "application/json"
        res.body = json.dumps(data)
        res.status = 200
        raise res
    else:
        bottle.redirect(reverse("/"))
Ejemplo n.º 24
0
    def _action_generic(self, action):
        if bottle.request.method != "POST":
            messages.error(_("Wrong HTTP method."))
            bottle.redirect(reverse("config_page", page_name="remote"))
        form = self.get_serial_form(bottle.request.POST.decode())
        if not form.data["serial"]:
            raise bottle.HTTPError(404, "serial not found")

        res = current_state.backend.perform("netboot", action,
                                            {"serial": form.data["serial"]})

        bottle.response.set_header("Content-Type", "application/json")
        return res
Ejemplo n.º 25
0
def login(next, session):
    if check_password(bottle.request.POST.get("password")):
        # re-generate session to prevent session fixation
        session.recreate()
        session["user_authenticated"] = True

        update_csrf_token(save_session=False)
        session.save()

        if next and is_safe_redirect(next, bottle.request.get_header("host")):
            bottle.redirect(next)
        else:
            bottle.redirect(reverse("index"))
Ejemplo n.º 26
0
def login(next, session):
    if check_password(bottle.request.POST.get("password")):
        # re-generate session to prevent session fixation
        session.recreate()
        session["user_authenticated"] = True

        update_csrf_token(save_session=False)
        session.save()

        if next and is_safe_redirect(next, bottle.request.get_header('host')):
            bottle.redirect(next)
        else:
            bottle.redirect(reverse("index"))
Ejemplo n.º 27
0
def change_lang(lang):
    """Change language of the interface.

    :param lang: language to set
    :raises: bottle.HTTPError if requested language is not installed
    """
    if lang in translations:
        if set_current_language(lang):
            bottle.request.app.lang = lang
        backlink = bottle.request.GET.get("backlink")
        if backlink and is_safe_redirect(backlink, bottle.request.get_header("host")):
            bottle.redirect(backlink)
        bottle.redirect(reverse("index"))
    else:
        raise bottle.HTTPError(404, "Language '%s' is not available." % lang)
Ejemplo n.º 28
0
def config_page_get(page_name):
    # redirect in case that guide is not passed
    if current_state.guide.enabled and page_name not in current_state.guide.available_tabs:
        bottle.redirect(reverse("config_page", page_name=current_state.guide.current))

    bottle.SimpleTemplate.defaults['active_config_page_key'] = page_name
    bottle.Jinja2Template.defaults['active_config_page_key'] = page_name
    ConfigPage = get_config_page(page_name)

    # test if page is enabled otherwise redirect to default
    if not ConfigPage.is_enabled() or not ConfigPage.is_visible():
        _redirect_to_default_location()

    config_page = ConfigPage()
    return config_page.render(active_config_page_key=page_name)
Ejemplo n.º 29
0
def config_page_get(page_name):
    # redirect in case that guide is not passed
    if current_state.guide.enabled and page_name not in current_state.guide.available_tabs:
        bottle.redirect(reverse("config_page", page_name=current_state.guide.current))

    bottle.SimpleTemplate.defaults["active_config_page_key"] = page_name
    bottle.Jinja2Template.defaults["active_config_page_key"] = page_name
    ConfigPage = get_config_page(page_name)

    # test if page is enabled otherwise redirect to default
    if not ConfigPage.is_enabled() or not ConfigPage.is_visible():
        _redirect_to_default_location()

    config_page = ConfigPage()
    return config_page.render(active_config_page_key=page_name)
Ejemplo n.º 30
0
def change_lang(lang):
    """Change language of the interface.

    :param lang: language to set
    :raises: bottle.HTTPError if requested language is not installed
    """
    if lang in translations:
        if set_current_language(lang):
            bottle.request.app.lang = lang
        backlink = bottle.request.GET.get('backlink')
        if backlink and is_safe_redirect(backlink, bottle.request.get_header('host')):
            bottle.redirect(backlink)
        bottle.redirect(reverse("index"))
    else:
        raise bottle.HTTPError(404, "Language '%s' is not available." % lang)
Ejemplo n.º 31
0
 def _check_post(self):
     if bottle.request.method != "POST":
         messages.error(_("Wrong HTTP method."))
         bottle.redirect(reverse("config_page", page_name="remote"))
Ejemplo n.º 32
0
 def _action_generate_ca(self):
     self._check_post()
     messages.info(_("Starting to generate CA for remote access."))
     current_state.backend.perform("remote", "generate_ca")
     # don't need to handle async_id (should influence all clients)
     bottle.redirect(reverse("config_page", page_name="remote"))
Ejemplo n.º 33
0
def reset_guide():
    current_state.backend.perform("web", "reset_guide")
    bottle.redirect(reverse("/"))
Ejemplo n.º 34
0
def leave_guide():
    current_state.backend.perform("web", "update_guide", {"enabled": False})
    bottle.redirect(reverse("/"))
Ejemplo n.º 35
0
def login_redirect():
    next_url = bottle.request.GET.get("next")
    if next_url and is_safe_redirect(next_url,
                                     bottle.request.get_header("host")):
        bottle.redirect(next_url)
    bottle.redirect(reverse("config_index"))
Ejemplo n.º 36
0
    def _prepare_device_fields(self, section, device, form_data, last=False):
        HINTS = {
            'password':
            _("WPA2 pre-shared key, that is required to connect to the "
              "network. Minimum length is 8 characters.")
        }

        def prefixed(name):
            return WifiHandler.prefixed(device["id"], name)

        # get corresponding band
        bands = [
            e for e in device["available_bands"]
            if e["hwmode"] == form_data["hwmode"]
        ]
        if not bands:
            # wrong hwmode selected pick the first one from available
            band = device["available_bands"][0]
            form_data["hwmode"] = device["available_bands"][0]["hwmode"]
        else:
            band = bands[0]

        wifi_main = section.add_section(
            name=prefixed("set_wifi"),
            title=None,
        )
        wifi_main.add_field(
            Checkbox,
            name=prefixed("device_enabled"),
            label=_("Enable Wi-Fi %s") % (device["id"] + 1),
            default=True,
        )
        wifi_main.add_field(Textbox,
                            name=prefixed("ssid"),
                            label=_("SSID"),
                            required=True,
                            validators=validators.ByteLenRange(
                                1, 32)).requires(prefixed("device_enabled"),
                                                 True)
        wifi_main.add_field(
            Checkbox,
            name=prefixed("ssid_hidden"),
            label=_("Hide SSID"),
            default=False,
            hint=
            _("If set, network is not visible when scanning for available networks."
              )).requires(prefixed("device_enabled"), True)

        wifi_main.add_field(
            Radio,
            name=prefixed("hwmode"),
            label=_("Wi-Fi mode"),
            args=[
                e for e in (("11g", "2.4 GHz (g)"), ("11a", "5 GHz (a)"))
                if e[0] in [b["hwmode"] for b in device["available_bands"]]
            ],
            hint=_(
                "The 2.4 GHz band is more widely supported by clients, but "
                "tends to have more interference. The 5 GHz band is a newer"
                " standard and may not be supported by all your devices. It "
                "usually has less interference, but the signal does not "
                "carry so well indoors.")).requires(prefixed("device_enabled"),
                                                    True)

        htmodes = (
            ("NOHT", _("Disabled")),
            ("HT20", _("802.11n - 20 MHz wide channel")),
            ("HT40", _("802.11n - 40 MHz wide channel")),
            ("VHT20", _("802.11ac - 20 MHz wide channel")),
            ("VHT40", _("802.11ac - 40 MHz wide channel")),
            ("VHT80", _("802.11ac - 80 MHz wide channel")),
        )
        wifi_main.add_field(
            Dropdown,
            name=prefixed("htmode"),
            label=_("802.11n/ac mode"),
            args=[e for e in htmodes if e[0] in band["available_htmodes"]],
            hint=
            _("Change this to adjust 802.11n/ac mode of operation. 802.11n with 40 MHz wide "
              "channels can yield higher throughput but can cause more interference in the "
              "network. If you don't know what to choose, use the default option with 20 MHz "
              "wide channel."
              )).requires(prefixed("device_enabled"), True).requires(
                  prefixed("hwmode"), lambda val: val in ("11g", "11a")
              )  # this req is added to rerender htmodes when hwmode changes

        channels = [("0", _("auto"))] + [
            (str(e["number"]),
             ("%d (%d MHz%s)" %
              (e["number"], e["frequency"], ", DFS" if e["radar"] else "")))
            for e in band["available_channels"]
        ]
        wifi_main.add_field(
            Dropdown,
            name=prefixed("channel"),
            label=_("Network channel"),
            default="0",
            args=channels,
        ).requires(prefixed("device_enabled"), True).requires(
            prefixed("hwmode"), lambda val: val in ("11g", "11a")
        )  # this req is added to rerender channel list when hwmode changes

        wifi_main.add_field(PasswordWithHide,
                            name=prefixed("password"),
                            label=_("Network password"),
                            required=True,
                            validators=validators.ByteLenRange(8, 63),
                            hint=HINTS['password']).requires(
                                prefixed("device_enabled"), True)

        if current_state.app == "config":
            # Guest wi-fi part
            guest_section = wifi_main.add_section(
                name=prefixed("set_guest_wifi"),
                title=_("Guest Wi-Fi"),
                description=_("Set guest Wi-Fi here."))
            guest_section.add_field(
                Checkbox,
                name=prefixed("guest_enabled"),
                label=_("Enable guest Wi-Fi"),
                default=False,
                hint=
                _("Enables Wi-Fi for guests, which is separated from LAN network. Devices "
                  "connected to this network are allowed to access the internet, but aren't "
                  "allowed to access other devices and the configuration interface of the "
                  "router. Parameters of the guest network can be set in <a href='%(url)s'>the "
                  "Guest network tab</a>. ") %
                dict(url=reverse("config_page", page_name="guest"))).requires(
                    prefixed("device_enabled"), True)
            guest_section.add_field(
                Textbox,
                name=prefixed("guest_ssid"),
                label=_("SSID for guests"),
                required=True,
                validators=validators.ByteLenRange(1, 32),
            ).requires(prefixed("guest_enabled"), True)
            guest_section.add_field(
                PasswordWithHide,
                name=prefixed("guest_password"),
                label=_("Password for guests"),
                required=True,
                default="",
                validators=validators.ByteLenRange(8, 63),
                hint=HINTS['password'],
            ).requires(prefixed("guest_enabled"), True)

        # Horizontal line separating wi-fi cards
        if not last:
            wifi_main.add_field(HorizontalLine,
                                name=prefixed("wifi-separator"),
                                class_="wifi-separator").requires(
                                    prefixed("device_enabled"), True)
Ejemplo n.º 37
0
Archivo: lan.py Proyecto: chlordk/foris
    def get_form(self):
        lan_form = fapi.ForisForm(
            "lan", self.data, filter=create_config_filter("dhcp", "network", "firewall", "sqm"))
        lan_main = lan_form.add_section(
            name="set_lan",
            title=_(self.userfriendly_title),
            description=_("This section contains settings for the local network (LAN). The provided"
                          " defaults are suitable for most networks. <br><strong>Note:</strong> If "
                          "you change the router IP address, all computers in LAN, probably "
                          "including the one you are using now, will need to obtain a <strong>new "
                          "IP address</strong> which does <strong>not</strong> happen <strong>"
                          "immediately</strong>. It is recommended to disconnect and reconnect all "
                          "LAN cables after submitting your changes to force the update. The next "
                          "page will not load until you obtain a new IP from DHCP (if DHCP enabled)"
                          " and you might need to <strong>refresh the page</strong> in your "
                          "browser.")
        )

        lan_main.add_field(Textbox, name="lan_ipaddr", label=_("Router IP address"),
                           nuci_path="uci.network.lan.ipaddr",
                           validators=validators.IPv4(),
                           hint=_("Router's IP address in inner network. Also defines the range of "
                                  "assigned IP addresses."))
        lan_main.add_field(Checkbox, name="dhcp_enabled", label=_("Enable DHCP"),
                           nuci_path="uci.dhcp.lan.ignore",
                           nuci_preproc=lambda val: not bool(int(val.value)), default=True,
                           hint=_("Enable this option to automatically assign IP addresses to "
                                  "the devices connected to the router."))
        lan_main.add_field(Textbox, name="dhcp_min", label=_("DHCP start"),
                           nuci_path="uci.dhcp.lan.start")\
            .requires("dhcp_enabled", True)
        lan_main.add_field(Textbox, name="dhcp_max", label=_("DHCP max leases"),
                           nuci_path="uci.dhcp.lan.limit")\
            .requires("dhcp_enabled", True)

        guest_network_section = lan_form.add_section(
            name="guest_network",
            title=_("Guest network"),
        )
        guest_network_section.add_field(
            Checkbox, name="guest_network_enabled",
            label=_("Enable guest network"), default=False,
            hint=_(
                "Guest network is used for <a href='%(url)s'>guest Wi-Fi</a>. It is separated  "
                "from your ordinary LAN network. Devices connected to this network are allowed "
                "to access the internet, but are not allowed to access other devices and "
                "the configuration interface of the router."
            ) % dict(url=reverse("config_page", page_name="wifi")),
            nuci_preproc=guest_network_enabled,
        )
        guest_network_section.add_field(
            Textbox, name="guest_network_subnet", label=_("Guest network"),
            nuci_preproc=generate_network_preprocessor(
                "uci.network.guest_turris.ipaddr",
                "uci.network.guest_turris.netmask",
                DEFAULT_GUEST_NETWORK,
                DEFAULT_GUEST_MASK,
            ),
            validators=[validators.IPv4Prefix()],
            hint=_(
                "You need to set the IP range for your guest network. It is necessary that "
                "the range is different than ranges on your other networks (LAN, WAN, VPN, etc.)."
            ),
        ).requires("guest_network_enabled", True)
        guest_network_section.add_field(
            Checkbox, name="guest_network_shapping", label=_("Guest Lan QoS"),
            nuci_preproc=parse_uci_bool,
            nuci_path="uci.sqm.guest_limit_turris.enabled",
            hint=_(
                "This option enables you to set a bandwidth limit for the guest network, "
                "so that your main network doesn't get slowed-down by it."
            ),
        ).requires("guest_network_enabled", True)
        guest_network_section.add_field(
            Number,
            name="guest_network_download", label=_("Download (kb/s)"),
            validators=[validators.PositiveInteger()],
            hint=_(
                "Download speed in guest network (in kilobits per second)."
            ),
            default=1024,
            nuci_path="uci.sqm.guest_limit_turris.upload",
        ).requires("guest_network_shapping", True)
        guest_network_section.add_field(
            Number,
            name="guest_network_upload", label=_("Upload (kb/s)"),
            validators=[validators.PositiveInteger()],
            hint=_(
                "Upload speed in guest network (in kilobits per second)."
            ),
            default=1024,
            nuci_path="uci.sqm.guest_limit_turris.download",
        ).requires("guest_network_shapping", True)

        def lan_form_cb(data):
            uci = Uci()
            config = Config("dhcp")
            uci.add(config)

            dhcp = Section("lan", "dhcp")
            config.add(dhcp)
            # FIXME: this would overwrite any unrelated DHCP options the user might have set.
            # Maybe we should get the current values, scan them and remove selectively the ones
            # with 6 in front of them? Or have some support for higher level of stuff in nuci.
            options = List("dhcp_option")
            options.add(Value(0, "6," + data['lan_ipaddr']))
            dhcp.add_replace(options)
            network = Config("network")
            uci.add(network)
            interface = Section("lan", "interface")
            network.add(interface)
            interface.add(Option("ipaddr", data['lan_ipaddr']))
            if data['dhcp_enabled']:
                dhcp.add(Option("ignore", "0"))
                dhcp.add(Option("start", data['dhcp_min']))
                dhcp.add(Option("limit", data['dhcp_max']))
            else:
                dhcp.add(Option("ignore", "1"))

            # qos data
            qos = {'enabled': False}
            if 'guest_network_shapping' in data and data['guest_network_shapping']:
                qos['enabled'] = True
                qos['download'] = data['guest_network_download']
                qos['upload'] = data['guest_network_upload']

            # update guest network configs
            guest_enabled = data.get("guest_network_enabled")
            guest_network_subnet = data.get("guest_network_subnet")
            if guest_network_subnet:
                network, prefix = data.get("guest_network_subnet").split("/")
            else:
                network, prefix = DEFAULT_GUEST_NETWORK, DEFAULT_GUEST_PREFIX

            # disable guest wifi when guest network is not enabled
            data = client.get(filter=wifi_filter())
            card_count = 0
            while data.find_child("uci.wireless.@wifi-device[%d]" % card_count):
                card_count += 1
            if not guest_enabled and card_count > 0:
                wireless = uci.add(Config("wireless"))
                for i in range(card_count):
                    guest_iface = wireless.add(Section("guest_iface_%d" % i, "wifi-iface"))
                    guest_iface.add(Option("disabled", "1"))

            guest_interfaces = ["guest_turris_%d" % e for e in range(card_count)]

            LanHandler.prepare_guest_configs(
                uci, guest_enabled, network, prefix, guest_interfaces, qos)

            return "edit_config", uci

        lan_form.add_callback(lan_form_cb)

        return lan_form
Ejemplo n.º 38
0
    def get_form(self):
        data = {}
        data["guest_enabled"] = self.backend_data["enabled"]
        data["guest_ipaddr"] = self.backend_data["ip"]
        data["guest_netmask"] = self.backend_data["netmask"]
        data["guest_dhcp_enabled"] = self.backend_data["dhcp"]["enabled"]
        data["guest_dhcp_start"] = self.backend_data["dhcp"]["start"]
        data["guest_dhcp_limit"] = self.backend_data["dhcp"]["limit"]
        data["guest_dhcp_leasetime"] = self.backend_data["dhcp"]["lease_time"] // 60 // 60
        data["guest_qos_enabled"] = self.backend_data["qos"]["enabled"]
        data["guest_qos_download"] = self.backend_data["qos"]["download"]
        data["guest_qos_upload"] = self.backend_data["qos"]["upload"]

        if self.data:
            # Update from post
            data.update(self.data)

        guest_form = fapi.ForisForm(
            "guest",
            data,
            validators=[
                validators.DhcpRangeValidator(
                    "guest_netmask",
                    "guest_dhcp_start",
                    "guest_dhcp_limit",
                    gettext(
                        "<strong>DHCP start</strong> and <strong>DHCP max leases</strong> "
                        "does not fit into <strong>Guest network netmask</strong>!"
                    ),
                    [
                        lambda data: not data["guest_enabled"],
                        lambda data: not data["guest_dhcp_enabled"],
                    ],
                )
            ],
        )
        guest_network_section = guest_form.add_section(
            name="guest_network",
            title=_(self.userfriendly_title),
            description=_(
                "Guest network is used for <a href='%(url)s'>guest Wi-Fi</a>. It is separated  "
                "from your ordinary LAN. Devices connected to this network are allowed "
                "to access the internet, but are not allowed to access the configuration "
                "interface of the this device nor the devices in LAN."
            )
            % dict(url=reverse("config_page", page_name="wifi")),
        )
        guest_network_section.add_field(
            Checkbox, name="guest_enabled", label=_("Enable guest network"), default=False
        )
        guest_network_section.add_field(
            Textbox,
            name="guest_ipaddr",
            label=_("Router IP in guest network"),
            default=DEFAULT_GUEST_IP,
            validators=validators.IPv4(),
            hint=_(
                "Router's IP address in the guest network. It is necessary that "
                "the guest network IPs are different from other networks "
                "(LAN, WAN, VPN, etc.)."
            ),
        ).requires("guest_enabled", True)
        guest_network_section.add_field(
            Textbox,
            name="guest_netmask",
            label=_("Guest network netmask"),
            default=DEFAULT_GUEST_MASK,
            validators=validators.IPv4Netmask(),
            hint=_("Network mask of the guest network."),
        ).requires("guest_enabled", True)

        guest_network_section.add_field(
            Checkbox,
            name="guest_dhcp_enabled",
            label=_("Enable DHCP"),
            preproc=lambda val: bool(int(val)),
            default=True,
            hint=_(
                "Enable this option to automatically assign IP addresses to "
                "the devices connected to the router."
            ),
        ).requires("guest_enabled", True)
        guest_network_section.add_field(
            Textbox, name="guest_dhcp_start", label=_("DHCP start")
        ).requires("guest_dhcp_enabled", True)
        guest_network_section.add_field(
            Textbox, name="guest_dhcp_limit", label=_("DHCP max leases")
        ).requires("guest_dhcp_enabled", True)
        guest_network_section.add_field(
            Textbox,
            name="guest_dhcp_leasetime",
            label=_("Lease time (hours)"),
            validators=[validators.InRange(1, 7 * 24)],
        ).requires("guest_dhcp_enabled", True)

        guest_network_section.add_field(
            Checkbox,
            name="guest_qos_enabled",
            label=_("Guest Lan QoS"),
            hint=_(
                "This option enables you to set a bandwidth limit for the guest network, "
                "so that your main network doesn't get slowed-down by it."
            ),
        ).requires("guest_enabled", True)

        guest_network_section.add_field(
            Number,
            name="guest_qos_download",
            label=_("Download (kb/s)"),
            validators=[validators.PositiveInteger()],
            hint=_("Download speed in guest network (in kilobits per second)."),
            default=1024,
        ).requires("guest_qos_enabled", True)
        guest_network_section.add_field(
            Number,
            name="guest_qos_upload",
            label=_("Upload (kb/s)"),
            validators=[validators.PositiveInteger()],
            hint=_("Upload speed in guest network (in kilobits per second)."),
            default=1024,
        ).requires("guest_qos_enabled", True)

        def guest_form_cb(data):
            if data["guest_enabled"]:
                msg = {
                    "enabled": data["guest_enabled"],
                    "ip": data["guest_ipaddr"],
                    "netmask": data["guest_netmask"],
                    "dhcp": {"enabled": data["guest_dhcp_enabled"]},
                    "qos": {"enabled": data["guest_qos_enabled"]},
                }
                if data["guest_dhcp_enabled"]:
                    msg["dhcp"]["start"] = int(data["guest_dhcp_start"])
                    msg["dhcp"]["limit"] = int(data["guest_dhcp_limit"])
                    msg["dhcp"]["lease_time"] = int(data["guest_dhcp_leasetime"]) * 60 * 60

                if data["guest_qos_enabled"]:
                    msg["qos"]["download"] = int(data["guest_qos_download"])
                    msg["qos"]["upload"] = int(data["guest_qos_upload"])
            else:
                msg = {"enabled": False}

            res = current_state.backend.perform("guest", "update_settings", msg)
            return "save_result", res  # store {"result": ...} to be used later...

        guest_form.add_callback(guest_form_cb)

        return guest_form
Ejemplo n.º 39
0
def login_redirect():
    next_url = bottle.request.GET.get("next")
    if next_url and is_safe_redirect(next_url, bottle.request.get_header("host")):
        bottle.redirect(next_url)
    bottle.redirect(reverse("config_index"))
Ejemplo n.º 40
0
Archivo: wifi.py Proyecto: CZ-NIC/foris
    def _prepare_device_fields(self, section, device, form_data, last=False):
        HINTS = {
            "password": _(
                "WPA2 pre-shared key, that is required to connect to the "
                "network. Minimum length is 8 characters."
            )
        }

        def prefixed(name):
            return WifiEditForm.prefixed(device["id"], name)

        # get corresponding band
        bands = [e for e in device["available_bands"] if e["hwmode"] == form_data["hwmode"]]
        if not bands:
            # wrong hwmode selected pick the first one from available
            band = device["available_bands"][0]
            form_data["hwmode"] = device["available_bands"][0]["hwmode"]
        else:
            band = bands[0]

        wifi_main = section.add_section(name=prefixed("set_wifi"), title=None)
        wifi_main.add_field(
            Checkbox,
            name=prefixed("device_enabled"),
            label=_("Enable Wi-Fi %s") % (device["id"] + 1),
            default=True,
        )
        wifi_main.add_field(
            Textbox,
            name=prefixed("ssid"),
            label=_("SSID"),
            required=True,
            validators=validators.ByteLenRange(1, 32),
        ).requires(prefixed("device_enabled"), True)
        wifi_main.add_field(
            Checkbox,
            name=prefixed("ssid_hidden"),
            label=_("Hide SSID"),
            default=False,
            hint=_("If set, network is not visible when scanning for available networks."),
        ).requires(prefixed("device_enabled"), True)

        wifi_main.add_field(
            Radio,
            name=prefixed("hwmode"),
            label=_("Wi-Fi mode"),
            args=[
                e
                for e in (("11g", "2.4 GHz (g)"), ("11a", "5 GHz (a)"))
                if e[0] in [b["hwmode"] for b in device["available_bands"]]
            ],
            hint=_(
                "The 2.4 GHz band is more widely supported by clients, but "
                "tends to have more interference. The 5 GHz band is a newer"
                " standard and may not be supported by all your devices. It "
                "usually has less interference, but the signal does not "
                "carry so well indoors."
            ),
        ).requires(prefixed("device_enabled"), True)

        htmodes = (
            ("NOHT", _("Disabled")),
            ("HT20", _("802.11n - 20 MHz wide channel")),
            ("HT40", _("802.11n - 40 MHz wide channel")),
            ("VHT20", _("802.11ac - 20 MHz wide channel")),
            ("VHT40", _("802.11ac - 40 MHz wide channel")),
            ("VHT80", _("802.11ac - 80 MHz wide channel")),
        )
        wifi_main.add_field(
            Dropdown,
            name=prefixed("htmode"),
            label=_("802.11n/ac mode"),
            args=[e for e in htmodes if e[0] in band["available_htmodes"]],
            hint=_(
                "Change this to adjust 802.11n/ac mode of operation. 802.11n with 40 MHz wide "
                "channels can yield higher throughput but can cause more interference in the "
                "network. If you don't know what to choose, use the default option with 20 MHz "
                "wide channel."
            ),
        ).requires(prefixed("device_enabled"), True).requires(
            prefixed("hwmode"), lambda val: val in ("11g", "11a")
        )  # this req is added to rerender htmodes when hwmode changes

        channels = [("0", _("auto"))] + [
            (
                str(e["number"]),
                ("%d (%d MHz%s)" % (e["number"], e["frequency"], ", DFS" if e["radar"] else "")),
            )
            for e in band["available_channels"]
        ]
        wifi_main.add_field(
            Dropdown,
            name=prefixed("channel"),
            label=_("Network channel"),
            default="0",
            args=channels,
        ).requires(prefixed("device_enabled"), True).requires(
            prefixed("hwmode"), lambda val: val in ("11g", "11a")
        )  # this req is added to rerender channel list when hwmode changes

        wifi_main.add_field(
            PasswordWithHide,
            name=prefixed("password"),
            label=_("Network password"),
            required=True,
            validators=validators.ByteLenRange(8, 63),
            hint=HINTS["password"],
        ).requires(prefixed("device_enabled"), True)

        if current_state.app == "config" and self.enable_guest:
            # Guest wi-fi part
            guest_section = wifi_main.add_section(
                name=prefixed("set_guest_wifi"),
                title=_("Guest Wi-Fi"),
                description=_("Set guest Wi-Fi here."),
            )
            guest_section.add_field(
                Checkbox,
                name=prefixed("guest_enabled"),
                label=_("Enable guest Wi-Fi"),
                default=False,
                hint=_(
                    "Enables Wi-Fi for guests, which is separated from LAN network. Devices "
                    "connected to this network are allowed to access the internet, but aren't "
                    "allowed to access other devices and the configuration interface of the "
                    "router. Parameters of the guest network can be set in <a href='%(url)s'>the "
                    "Guest network tab</a>."
                )
                % dict(url=reverse("config_page", page_name="guest")),
            ).requires(prefixed("device_enabled"), True)
            guest_section.add_field(
                Textbox,
                name=prefixed("guest_ssid"),
                label=_("SSID for guests"),
                required=True,
                validators=validators.ByteLenRange(1, 32),
            ).requires(prefixed("guest_enabled"), True)
            guest_section.add_field(
                PasswordWithHide,
                name=prefixed("guest_password"),
                label=_("Password for guests"),
                required=True,
                default="",
                validators=validators.ByteLenRange(8, 63),
                hint=HINTS["password"],
            ).requires(prefixed("guest_enabled"), True)

        # Horizontal line separating wi-fi cards
        if not last:
            wifi_main.add_field(
                HorizontalLine, name=prefixed("wifi-separator"), class_="wifi-separator"
            ).requires(prefixed("device_enabled"), True)
Ejemplo n.º 41
0
    def get_form(self):
        data = {}
        data["guest_enabled"] = self.backend_data["enabled"]
        data["guest_ipaddr"] = self.backend_data["ip"]
        data["guest_netmask"] = self.backend_data["netmask"]
        data["guest_dhcp_enabled"] = self.backend_data["dhcp"]["enabled"]
        data["guest_dhcp_start"] = self.backend_data["dhcp"]["start"]
        data["guest_dhcp_limit"] = self.backend_data["dhcp"]["limit"]
        data["guest_dhcp_leasetime"] = self.backend_data["dhcp"]["lease_time"] // 60 // 60
        data["guest_qos_enabled"] = self.backend_data["qos"]["enabled"]
        data["guest_qos_download"] = self.backend_data["qos"]["download"]
        data["guest_qos_upload"] = self.backend_data["qos"]["upload"]

        if self.data:
            # Update from post
            data.update(self.data)

        guest_form = fapi.ForisForm(
            "guest",
            data,
            validators=[
                validators.DhcpRangeValidator(
                    "guest_netmask",
                    "guest_dhcp_start",
                    "guest_dhcp_limit",
                    gettext(
                        "<strong>DHCP start</strong> and <strong>DHCP max leases</strong> "
                        "does not fit into <strong>Guest network netmask</strong>!"
                    ),
                    [
                        lambda data: not data.get("guest_enabled"),
                        lambda data: not data.get("guest_dhcp_enabled"),
                    ],
                ),
                validators.DhcpRangeRouterIpValidator(
                    "guest_ipaddr",
                    "guest_netmask",
                    "guest_dhcp_start",
                    "guest_dhcp_limit",
                    gettext(
                        "<strong>Router IP</strong> should not be within DHCP range "
                        "defined by <strong>DHCP start</strong> and <strong>DHCP max leases "
                        "</strong>"
                    ),
                    [
                        lambda data: not data.get("guest_dhcp_enabled"),
                        lambda data: not data.get("guest_enabled"),
                    ],
                ),
            ],
        )
        guest_network_section = guest_form.add_section(
            name="guest_network",
            title=_(self.userfriendly_title),
            description=_(
                "Guest network is used for <a href='%(url)s'>guest Wi-Fi</a>. It is separated  "
                "from your ordinary LAN. Devices connected to this network are allowed "
                "to access the internet, but are not allowed to access the configuration "
                "interface of this device nor the devices in LAN."
            )
            % dict(url=reverse("config_page", page_name="wifi")),
        )
        guest_network_section.add_field(
            Checkbox, name="guest_enabled", label=_("Enable guest network"), default=False
        )
        guest_network_section.add_field(
            Textbox,
            name="guest_ipaddr",
            label=_("Router IP in guest network"),
            default=DEFAULT_GUEST_IP,
            validators=validators.IPv4(),
            hint=_(
                "Router's IP address in the guest network. It is necessary that "
                "the guest network IPs are different from other networks "
                "(LAN, WAN, VPN, etc.)."
            ),
        ).requires("guest_enabled", True)
        guest_network_section.add_field(
            Textbox,
            name="guest_netmask",
            label=_("Guest network netmask"),
            default=DEFAULT_GUEST_MASK,
            validators=validators.IPv4Netmask(),
            hint=_("Network mask of the guest network."),
        ).requires("guest_enabled", True)

        guest_network_section.add_field(
            Checkbox,
            name="guest_dhcp_enabled",
            label=_("Enable DHCP"),
            preproc=lambda val: bool(int(val)),
            default=True,
            hint=_(
                "Enable this option to automatically assign IP addresses to "
                "the devices connected to the router."
            ),
        ).requires("guest_enabled", True)
        guest_network_section.add_field(
            Textbox, name="guest_dhcp_start", label=_("DHCP start")
        ).requires("guest_dhcp_enabled", True)
        guest_network_section.add_field(
            Textbox, name="guest_dhcp_limit", label=_("DHCP max leases")
        ).requires("guest_dhcp_enabled", True)
        guest_network_section.add_field(
            Textbox,
            name="guest_dhcp_leasetime",
            label=_("Lease time (hours)"),
            validators=[validators.InRange(1, 7 * 24)],
        ).requires("guest_dhcp_enabled", True)

        guest_network_section.add_field(
            Checkbox,
            name="guest_qos_enabled",
            label=_("Guest Lan QoS"),
            hint=_(
                "This option enables you to set a bandwidth limit for the guest network, "
                "so that your main network doesn't get slowed-down by it."
            ),
        ).requires("guest_enabled", True)

        guest_network_section.add_field(
            Number,
            name="guest_qos_download",
            label=_("Download (kb/s)"),
            validators=[validators.PositiveInteger()],
            hint=_("Download speed in guest network (in kilobits per second)."),
            default=1024,
        ).requires("guest_qos_enabled", True)
        guest_network_section.add_field(
            Number,
            name="guest_qos_upload",
            label=_("Upload (kb/s)"),
            validators=[validators.PositiveInteger()],
            hint=_("Upload speed in guest network (in kilobits per second)."),
            default=1024,
        ).requires("guest_qos_enabled", True)

        def guest_form_cb(data):
            if data["guest_enabled"]:
                msg = {
                    "enabled": data["guest_enabled"],
                    "ip": data["guest_ipaddr"],
                    "netmask": data["guest_netmask"],
                    "dhcp": {"enabled": data["guest_dhcp_enabled"]},
                    "qos": {"enabled": data["guest_qos_enabled"]},
                }
                if data["guest_dhcp_enabled"]:
                    msg["dhcp"]["start"] = int(data["guest_dhcp_start"])
                    msg["dhcp"]["limit"] = int(data["guest_dhcp_limit"])
                    msg["dhcp"]["lease_time"] = int(data["guest_dhcp_leasetime"]) * 60 * 60

                if data["guest_qos_enabled"]:
                    msg["qos"]["download"] = int(data["guest_qos_download"])
                    msg["qos"]["upload"] = int(data["guest_qos_upload"])
            else:
                msg = {"enabled": False}

            res = current_state.backend.perform("guest", "update_settings", msg)
            return "save_result", res  # store {"result": ...} to be used later...

        guest_form.add_callback(guest_form_cb)

        return guest_form
Ejemplo n.º 42
0
def leave_guide():
    current_state.backend.perform("web", "update_guide", {
        "enabled": False,
    })
    bottle.redirect(reverse("/"))
Ejemplo n.º 43
0
    def _add_wifi_section(self,
                          wifi_section,
                          wifi_card,
                          radio_to_iface,
                          post_data,
                          nuci_data,
                          last=False):
        HINTS = {
            'password':
            _("WPA2 pre-shared key, that is required to connect to the "
              "network. Minimum length is 8 characters.")
        }

        radio_index = int(wifi_card['name'][3:])
        iface_index = radio_to_iface.get('radio%s' % radio_index)
        if iface_index is None:
            # Interface is not present in the wireless config - skip this radio
            return None

        def prefixed_name(name):
            return "radio%s-%s" % (radio_index, name)

        wifi_main = wifi_section.add_section(
            name=prefixed_name("set_wifi"),
            title=None,
        )

        wifi_main.add_field(Hidden,
                            name=prefixed_name("iface_section"),
                            nuci_path="uci.wireless.@wifi-iface[%s]" %
                            iface_index,
                            nuci_preproc=lambda val: val.name)

        # Use numbering starting from one. In rare cases, it may happen that the first radio
        # is not radio0, or that there's a gap between radio numbers, but it should not happen
        # on most of the setups.
        wifi_main.add_field(Checkbox,
                            name=prefixed_name("wifi_enabled"),
                            label=_("Enable Wi-Fi %s") % (radio_index + 1),
                            default=True,
                            nuci_path="uci.wireless.@wifi-iface[%s].disabled" %
                            iface_index,
                            nuci_preproc=lambda val: not bool(int(val.value)))
        wifi_main.add_field(
            Textbox,
            name=prefixed_name("ssid"),
            label=_("SSID"),
            nuci_path="uci.wireless.@wifi-iface[%s].ssid" % iface_index,
            required=True,
            validators=validators.ByteLenRange(1, 32)).requires(
                prefixed_name("wifi_enabled"), True)

        wifi_main.add_field(
            Checkbox,
            name=prefixed_name("ssid_hidden"),
            label=_("Hide SSID"),
            default=False,
            nuci_path="uci.wireless.@wifi-iface[%s].hidden" % iface_index,
            hint=
            _("If set, network is not visible when scanning for available networks."
              )).requires(prefixed_name("wifi_enabled"), True)

        channels_2g4, channels_5g = self._get_channels(wifi_card)

        is_dual_band = False
        # hwmode choice for dual band devices
        if len(channels_2g4) > 1 and len(channels_5g) > 1:
            is_dual_band = True
            wifi_main.add_field(
                Radio,
                name=prefixed_name("hwmode"),
                label=_("Wi-Fi mode"),
                default="11g",
                args=(("11g", "2.4 GHz (g)"), ("11a", "5 GHz (a)")),
                nuci_path="uci.wireless.radio%s.hwmode" % radio_index,
                nuci_preproc=lambda x: x.value.replace("n", ""
                                                       ),  # old configs used
                # 11ng/11na
                hint=
                _("The 2.4 GHz band is more widely supported by clients, but "
                  "tends to have more interference. The 5 GHz band is a newer"
                  " standard and may not be supported by all your devices. It "
                  "usually has less interference, but the signal does not "
                  "carry so well indoors.")).requires(
                      prefixed_name("wifi_enabled"), True)

        htmodes = (("NOHT", _("Disabled")),
                   ("HT20", _("802.11n - 20 MHz wide channel")),
                   ("HT40", _("802.11n - 40 MHz wide channel")))

        # Allow VHT modes only if the card has the capabilities and 5 GHz band is selected
        hwmode = self._get_value(post_data, nuci_data,
                                 "radio%s-hwmode" % radio_index,
                                 "uci.wireless.radio%s.hwmode" % radio_index)
        allow_vht = wifi_card['vht-capabilities'] and hwmode == "11a"

        if allow_vht:
            htmodes += (
                ("VHT20", _("802.11ac - 20 MHz wide channel")),
                ("VHT40", _("802.11ac - 40 MHz wide channel")),
                ("VHT80", _("802.11ac - 80 MHz wide channel")),
            )

        wifi_main.add_field(
            Dropdown,
            name=prefixed_name("htmode"),
            label=_("802.11n/ac mode"),
            args=htmodes,
            nuci_path="uci.wireless.radio%s.htmode" % radio_index,
            hint=
            _("Change this to adjust 802.11n/ac mode of operation. 802.11n with 40 MHz wide "
              "channels can yield higher throughput but can cause more interference in the "
              "network. If you don't know what to choose, use the default option with 20 MHz "
              "wide channel.")).requires(prefixed_name("wifi_enabled"), True)

        # 2.4 GHz channels
        if len(channels_2g4) > 1:
            field_2g4 = wifi_main.add_field(
                Dropdown,
                name=prefixed_name("channel2g4"),
                label=_("Network channel"),
                default=channels_2g4[0][0],
                args=channels_2g4,
                nuci_path="uci.wireless.radio%s.channel" %
                radio_index).requires(prefixed_name("wifi_enabled"), True)

            if is_dual_band:
                field_2g4.requires(prefixed_name("hwmode"), "11g")

        # 5 GHz channels
        if len(channels_5g) > 1:
            field_5g = wifi_main.add_field(
                Dropdown,
                name=prefixed_name("channel5g"),
                label=_("Network channel"),
                default=channels_5g[0][0],
                args=channels_5g,
                nuci_path="uci.wireless.radio%s.channel" %
                radio_index).requires(prefixed_name("wifi_enabled"), True)

            if is_dual_band:
                field_5g.requires(prefixed_name("hwmode"), "11a")

        wifi_main.add_field(
            Password,
            name=prefixed_name("key"),
            label=_("Network password"),
            nuci_path="uci.wireless.@wifi-iface[%s].key" % iface_index,
            required=True,
            validators=validators.ByteLenRange(8, 63),
            hint=HINTS['password']).requires(prefixed_name("wifi_enabled"),
                                             True)

        # Guest wi-fi part
        guest_section = wifi_main.add_section(
            name=prefixed_name("set_guest_wifi"),
            title=_("Guest Wi-Fi"),
            description=_("Set guest Wi-Fi here."))

        guest_section.add_field(
            Checkbox,
            name=prefixed_name("guest_enabled"),
            label=_("Enable guest Wi-Fi"),
            default=False,
            nuci_path="uci.wireless.guest_iface_%s.disabled" % iface_index,
            nuci_preproc=lambda value: not parse_uci_bool(value),
            hint=
            _("Enables Wi-Fi for guests, which is separated from LAN network. Devices "
              "connected to this network are allowed to access the internet, but aren't "
              "allowed to access other devices and the configuration interface of the router. "
              "Parameters of the guest network can be set in <a href='%(url)s'>the LAN tab</a>. "
              ) % dict(url=reverse("config_page", page_name="lan"))).requires(
                  prefixed_name("wifi_enabled"), True)

        default_ssid = self._get_value(
            post_data,
            nuci_data,
            prefixed_name("ssid"),
            "uci.wireless.@wifi-iface[%s].ssid" % iface_index,
            "Turris",
        )
        default_guest_ssid = self._get_value(
            post_data, nuci_data, prefixed_name("guest_ssid"),
            "uci.wireless.guest_iface_%s.ssid" % iface_index,
            "%s-guest" % default_ssid)
        guest_section.add_field(Textbox,
                                name=prefixed_name("guest_ssid"),
                                label=_("SSID for guests"),
                                nuci_path="uci.wireless.guest_iface_%s.ssid" %
                                iface_index,
                                required=True,
                                validators=validators.ByteLenRange(1, 32),
                                default=default_guest_ssid).requires(
                                    prefixed_name("guest_enabled"), True)

        guest_section.add_field(
            Password,
            name=prefixed_name("guest_key"),
            label=_("Password for guests"),
            nuci_path="uci.wireless.guest_iface_%s.key" % iface_index,
            required=True,
            default="",
            validators=validators.ByteLenRange(8, 63),
            hint=HINTS['password'],
        ).requires(prefixed_name("guest_enabled"), True)

        # Horizontal line separating wi-fi cards
        if not last:
            wifi_main.add_field(HorizontalLine,
                                name=prefixed_name("wifi-separator"),
                                class_="wifi-separator").requires(
                                    prefixed_name("wifi_enabled"), True)
Ejemplo n.º 44
0
def reset_guide():
    current_state.backend.perform("web", "reset_guide")
    bottle.redirect(reverse("/"))