Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: keyboard shortcuts #185

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const loginLimiter = rateLimit({
max: Number(process.env.ZT_TRIES_TO_BAN) || 50, // limit each IP to 50 requests per windowMs
message: {
status: 429,
error: "Too many login attempts, please try again in 15 minutes.",
error: "tooManyAttemps",
},
});

Expand Down
4 changes: 2 additions & 2 deletions backend/services/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ export async function authorize(username, password, callback) {
throw err;
}
const user = users.find({ username: username });
if (!user.value()) return callback(new Error("Invalid username or password")); // If return "user not found" someone can do a user listing
if (!user.value()) return callback(new Error("logInFailed")); // If return "user not found" someone can do a user listing
const verified = await verifyHash(password, user.value()["password_hash"]);
if (verified) {
return callback(null, user.value());
} else {
return callback(new Error("Invalid username or password"));
return callback(new Error("logInFailed"));
}
}

Expand Down
6 changes: 6 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "frontend",
"private": true,
"type": "module",
"dependencies": {
"@fontsource/roboto": "^4.5.8",
"@material-ui/core": "^4.12.4",
Expand All @@ -11,11 +12,16 @@
"codemirror": "^5.62.3",
"date-fns": "^2.29.2",
"history": "^5.3.0",
"i18next": "^23.5.1",
"i18next-browser-languagedetector": "^7.1.0",
"i18next-http-backend": "^2.2.2",
"ipaddr.js": "^2.0.1",
"lodash": "^4.17.21",
"ninja-keys": "^1.2.2",
"react": "^17.0.2",
"react-data-table-component": "^6.11.8",
"react-dom": "^17.0.2",
"react-i18next": "^13.3.0",
"react-is": "^17.0.2",
"react-router-dom": "^5.2.0",
"react-use": "^17.4.0",
Expand Down
61 changes: 61 additions & 0 deletions frontend/public/locales/en/common.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"flowRules": "Flow Rules",
"createNetwork": "Create A Network",
"createOneNetwork": "Please create at least one network",
"controllerNetworks": "Controller networks",
"network_one": "Network",
"network_other": "Networks",
"controllerAddress": "Network controller address",
"loginToContinue": "Please, Log In to continue",
"zerouiDesc": "ZeroUI - ZeroTier Controller Web UI - is a web user interface for a self-hosted ZeroTier network controller.",
"logIn": "Log In",
"logInToken": "Token Log In",
"cancel": "Cancel",
"management": "Management",
"deleteNetwork": "Delete Network",
"deleteAlert": "This action cannot be undone.",
"deleteNetworkConfirm": "Are you sure you want to delete this network?",
"deleteMemberConfirm": "Are you sure you want to delete this member?",
"delete": "Delete",
"logOut": "Log out",
"advancedFeature": "ADVANCED FEATURE",
"noDevices": "No devices have joined this network. Use the app on your devices to join",
"member_one": "Member",
"member_other": "Members",
"addMemberMan": "Manually Add Member",
"name": "Name",
"description": "Description",
"allowBridging": "Allow Ethernet Bridging",
"noAutoIP": "Do Not Auto-Assign IPs",
"capabilities": "Capabilities",
"noCapDef": "No capabilities defined",
"tags": "Tags",
"noTagDef": "No tags defined",
"authorized": "Authorized",
"address": "Address",
"ips": "Managed IPs",
"status": "Last seen",
"version": "Version",
"physIp": "Physical IP",
"latency": "Latency",
"settings": "Settings",
"generalSettings": "General settings",
"netId": "Network ID",
"accessControl": "Access control",
"public": "Public",
"private": "Private",
"managedRoutes": "Managed routes",
"addRoute": "Add route",
"target": "Target",
"via": "Via",
"start": "Start",
"end": "End",
"ipv4AutoAssign": "IPv4 Auto-Assign",
"autoAssignPool": "IPv4 Auto-Assign",
"addIPv4Pool": "Add IPv4 Pool",
"multicastLimit": "Multicast Recipient Limit",
"enaBroadcast": "Enable Broadcast",
"logInFailed": "Invalid username or password",
"tooManyAttemps": "Too many login attempts, please try again in 15 minutes.",
"language": "Language"
}
61 changes: 61 additions & 0 deletions frontend/public/locales/es-ES/common.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"flowRules": "Reglas de flujo",
"createNetwork": "Crear una red",
"createOneNetwork": "Por favor, crea al menos una red",
"controllerNetworks": "Controlador de redes",
"network_one": "Red",
"network_other": "Redes",
"controllerAddress": "Dirección del controlador",
"loginToContinue": "Por favor, inicia sesión para continuar",
"zerouiDesc": "ZeroUI - ZeroTier Controller Web UI - es una interfaz de usuario web para un controlador de red ZeroTier self-hosted.",
"logIn": "Iniciar sesión",
"logInToken": "Iniciar sesión con token",
"cancel": "Cancelar",
"management": "Gestión",
"deleteNetwork": "Borrar red",
"deleteAlert": "Esta acción no puede ser revertida.",
"deleteNetworkConfirm": "¿Seguro que deseas borrar esta red?",
"deleteMemberConfirm": "¿Seguro que deseas borrar este usuario?",
"delete": "Borrar",
"logOut": "Cerrar sesión",
"advancedFeature": "CARACTERÍSTICA AVANZADA",
"noDevices": "Ningún dispositivo se ha unido a esta red. Utilice la aplicación en sus dispositivos para unirse",
"member_one": "Miembro",
"member_other": "Miembros",
"addMemberMan": "Añadir miembro manualmente",
"name": "Nombre",
"description": "Descripción",
"allowBridging": "Permitir puente Ethernet",
"noAutoIP": "No autoasignar IPs",
"capabilities": "Permisos",
"noCapDef": "No hay permisos definidos",
"tags": "Etiquetas",
"noTagDef": "No hay etiquetas definidas",
"authorized": "Autorizado",
"address": "Dirección",
"ips": "IPs asignadas",
"status": "Visto por última vez",
"version": "Versión",
"physIp": "IP pública",
"latency": "Latencia",
"settings": "Ajustes",
"generalSettings": "Ajustes generales",
"netId": "ID de red",
"accessControl": "Control de acceso",
"public": "Público",
"private": "Privado",
"managedRoutes": "Rutas gestionadas",
"addRoute": "Añadir ruta",
"target": "Objetivo",
"via": "Vía",
"start": "Inicio",
"end": "Final",
"autoAssignPool": "Rango de IPv4 autoasignables",
"ipv4AutoAssign": "IPv4 Auto-Assign",
"addIPv4Pool": "Añadir rango IPv4",
"multicastLimit": "Límite de destinatarios multicast",
"enaBroadcast": "Habilitar broadcast",
"logInFailed": "Nombre de usuario o contraseña incorrecto",
"tooManyAttemps": "Demasiados intentos de inicio de sesión. Vuelvee a intentarlo en 15 minutos",
"language": "Idioma"
}
12 changes: 7 additions & 5 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import "@fontsource/roboto";

import { BrowserRouter, Route, Redirect, Switch } from "react-router-dom";

import Theme from "./components/Theme";
import Bar from "./components/Bar";
import Theme from "./components/Theme/Theme.jsx";
import Bar from "./components/Bar/Bar.jsx";

import Home from "./routes/Home";
import NotFound from "./routes/NotFound";
import Network from "./routes/Network/Network";
import Home from "./routes/Home/Home.jsx";
import NotFound from "./routes/NotFound/NotFound.jsx";
import Network from "./routes/Network/Network.jsx";
import Settings from "./routes/Settings/Settings.jsx";

function App() {
return (
Expand All @@ -17,6 +18,7 @@ function App() {
<Switch>
<Route exact path="/" component={Home} />
<Route path="/network/:nwid" component={Network} />
<Route path="/settings" component={Settings} />
<Route path="/404" component={NotFound} />
<Redirect to="/404" />
</Switch>
Expand Down
74 changes: 62 additions & 12 deletions frontend/src/components/Bar/Bar.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import logo from "./assets/logo.png";

import { useState } from "react";
import { Link as RouterLink, useHistory } from "react-router-dom";
import { useLocalStorage } from "react-use";
import { useEffect, useRef, useState } from "react";
import { Redirect, Link as RouterLink, useHistory } from "react-router-dom";
import { useLocalStorage, useWindowScroll } from "react-use";

import {
AppBar,
Expand All @@ -15,16 +15,56 @@ import {
MenuItem,
Link,
} from "@material-ui/core";
import MenuIcon from "@material-ui/icons/Menu";
import MenuIcon from "@material-ui/icons/Menu.js";

import LogIn from "components/LogIn";
import LogIn from "components/LogIn/LogIn.jsx";
import "ninja-keys";

import { useTranslation } from "react-i18next";
import API from "utils/API.js";
import { generateNetworkConfig } from "utils/NetworkConfig.js";

function Bar() {
const ninjaKeys = useRef(null);
const history = useHistory();
const { t, i18n } = useTranslation();

const [hotkeys, setHotkeys] = useState([
{
id: "Settings",
title: t("settings"),
hotkey: "cmd+shift+s",
handler: () => {
history.push("/settings");
},
},
{
id: "createNet",
title: t("createNetwork"),
hotkey: "cmd+shift+n",
handler: () => {
createNetwork();
},
},
{
id: "LogOut",
title: t("logOut"),
hotkey: "cmd+shift+g",
handler: () => {
onLogOutClick();
},
},
]);

const [loggedIn, setLoggedIn] = useLocalStorage("loggedIn", false);
const [disabledAuth] = useLocalStorage("disableAuth", false);
const [anchorEl, setAnchorEl] = useState(null);

const history = useHistory();
const createNetwork = async () => {
const network = await API.post("network", generateNetworkConfig());
console.log(network);
history.push("/network/" + network.data["config"]["id"]);
};

const openMenu = (event) => {
setAnchorEl(event.currentTarget);
Expand All @@ -41,16 +81,22 @@ function Bar() {
history.go(0);
};

useEffect(() => {
if (ninjaKeys.current) {
ninjaKeys.current.data = hotkeys;
}
}, []);

const menuItems = [
// TODO: add settings page
// {
// name: "Settings",
// to: "/settings",
// },
{
name: t("settings"),
to: "/settings",
},
...(!disabledAuth
? [
{
name: "Log out",
name: t("logOut"),
divide: true,
onClick: onLogOutClick,
},
Expand All @@ -64,6 +110,11 @@ function Bar() {
style={{ background: "#000000" }}
position="static"
>
{loggedIn && (
<>
<ninja-keys ref={ninjaKeys}></ninja-keys>
</>
)}
<Toolbar>
<Box display="flex" flexGrow={1}>
<Typography color="inherit" variant="h6">
Expand Down Expand Up @@ -115,7 +166,6 @@ function Bar() {
key={index}
onClick={() => {
closeMenu();

menuItem.onClick();
}}
>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Bar/index.jsx
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { default } from "./Bar";
export { default } from "./Bar.jsx";
24 changes: 14 additions & 10 deletions frontend/src/components/HomeLoggedIn/HomeLoggedIn.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { useState, useEffect } from "react";
import { useHistory } from "react-router-dom";

import { Divider, Button, Grid, Typography, Box } from "@material-ui/core";
import useStyles from "./HomeLoggedIn.styles";
import useStyles from "./HomeLoggedIn.styles.jsx";

import NetworkButton from "./components/NetworkButton";
import NetworkButton from "./components/NetworkButton/NetworkButton.jsx";

import API from "utils/API";
import { generateNetworkConfig } from "utils/NetworkConfig";
import API from "utils/API.js";
import { generateNetworkConfig } from "utils/NetworkConfig.js";

import { useTranslation } from "react-i18next";

function HomeLoggedIn() {
const [networks, setNetworks] = useState([]);
Expand All @@ -30,6 +32,8 @@ function HomeLoggedIn() {
fetchData();
}, []);

const { t, i18n } = useTranslation();

return (
<div className={classes.root}>
<Button
Expand All @@ -38,19 +42,19 @@ function HomeLoggedIn() {
className={classes.createBtn}
onClick={createNetwork}
>
Create A Network
{t("createNetwork")}
</Button>
<Divider />
<Grid container spacing={3} className={classes.container}>
<Grid item xs={6}>
<Typography variant="h5">Controller networks</Typography>
{networks[0] && "Network controller address"}
<Typography variant="h5">{t("controllerNetworks")}</Typography>
{networks[0] && t("controllerAddress")}
<Box fontWeight="fontWeightBold">
{networks[0] && networks[0]["id"].slice(0, 10)}
{networks[0] && String(networks[0]["id"]).slice(0, 10)}
</Box>
</Grid>
<Grid item xs="auto">
<Typography>Networks</Typography>
<Typography>{t("network", { count: networks.length })}</Typography>
<Grid item>
{networks[0] ? (
networks.map((network) => (
Expand All @@ -59,7 +63,7 @@ function HomeLoggedIn() {
</Grid>
))
) : (
<div>Please create at least one network</div>
<div>{t("createOneNetwork")}</div>
)}
</Grid>
</Grid>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/HomeLoggedIn/index.jsx
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { default } from "./HomeLoggedIn";
export { default } from "./HomeLoggedIn.jsx";
Loading