feat: allow restrict Pomodoro via password

- introduce password flag in server command line options
- update clientCommand model
- add password requirement for controlling the Pomodoro timer
- document password in README
This commit is contained in:
Sebastian Mark 2024-10-21 15:36:26 +02:00
parent 8deb642a7e
commit f991ba885d
5 changed files with 38 additions and 26 deletions

View file

@ -22,14 +22,18 @@ Both client commands (sent to the server) and server messages (sent to the clien
### Client Commands ### Client Commands
Clients communicate with the server by sending JSON-encoded commands. Each command must include a `command` field specifying the action to perform. Here are the available commands: Clients communicate with the server by sending JSON-encoded commands. Each command must include a `command` field specifying the action to perform and the control `password` required to manage the Pomodoro timer. The password is set by the server (see [Usage](#usage)).
If the client sends a command with an incorrect password it will not be allowed to control the Pomodoro, but will still receive server messages (see below). By default the password is an empty string which allows everyone to control the Pomodoro. In this case, the `password` field may be omitted in the client's command.
Here are the available commands:
| Command | Action | Example Sent by Client | | Command | Action | Example Sent by Client |
|----------|-------------------------------------|-----------------------------------| |----------|-------------------------------------|-----------------------------------|
| `start` | Starts a new Pomodoro session | `{"command": "start"}` | | `start` | Starts a new Pomodoro session | `{"command": "start", "password": ""}` |
| `pause` | Pauses the current session | `{"command": "pause"}` | | `pause` | Pauses the current session | `{"command": "pause", "password": ""}` |
| `resume` | Resumes a paused session | `{"command": "resume"}` | | `resume` | Resumes a paused session | `{"command": "resume", "password": ""}` |
| `reset` | Stops and resets the current session| `{"command": "reset"}` | | `reset` | Stops and resets the current session| `{"command": "reset", "password": ""}` |
#### Optional Start Parameters #### Optional Start Parameters
@ -39,6 +43,7 @@ Example:
```json ```json
{ {
command: "start", command: "start",
password: "foobar",
config: { config: {
"work": 10, // Length of the work session in seconds "work": 10, // Length of the work session in seconds
"shortBreak": 5, // Length of the short break in seconds "shortBreak": 5, // Length of the short break in seconds

View file

@ -14,12 +14,14 @@ func Start() {
// Define CLI flags for ListenAddress and ListenPort // Define CLI flags for ListenAddress and ListenPort
listenAddress := flag.String("listenAddress", shared.DefaultServerConfig.ListenAddress, "IP address to listen on") listenAddress := flag.String("listenAddress", shared.DefaultServerConfig.ListenAddress, "IP address to listen on")
listenPort := flag.Int("listenPort", shared.DefaultServerConfig.ListenPort, "Port to listen on") listenPort := flag.Int("listenPort", shared.DefaultServerConfig.ListenPort, "Port to listen on")
password := flag.String("password", "", "Control password for pomodoro session (optional)")
flag.Parse() flag.Parse()
serverConfig := models.GoTomatoServerConfig{ serverConfig := models.GoTomatoServerConfig{
ListenAddress: *listenAddress, ListenAddress: *listenAddress,
ListenPort: *listenPort, ListenPort: *listenPort,
} }
shared.PomodoroPassword = *password
listen := fmt.Sprintf("%s:%d", serverConfig.ListenAddress, serverConfig.ListenPort) listen := fmt.Sprintf("%s:%d", serverConfig.ListenAddress, serverConfig.ListenPort)

View file

@ -16,3 +16,5 @@ func ResetToDefault() models.ServerMessage {
Paused: false, Paused: false,
} }
} }
var PomodoroPassword string

View file

@ -30,26 +30,28 @@ func handleClientCommands(ws *websocket.Conn) {
continue continue
} }
// Process the command // Process the command if pomodoro password matches
switch clientCommand.Command { if clientCommand.Password == shared.PomodoroPassword {
case "start": switch clientCommand.Command {
if !pomodoro.IsPomodoroOngoing() { case "start":
if clientCommand.Config != shared.UnsetPomodoroConfig { if !pomodoro.IsPomodoroOngoing() {
pomodoroConfig = clientCommand.Config if clientCommand.Config != shared.UnsetPomodoroConfig {
pomodoroConfig = clientCommand.Config
}
go pomodoro.RunPomodoro(pomodoroConfig) // Start the timer with the list of clients
}
case "stop":
if pomodoro.IsPomodoroOngoing() {
pomodoro.ResetPomodoro() // Reset Pomodoro
}
case "pause":
if pomodoro.IsPomodoroOngoing() && !pomodoro.IsPomodoroPaused() {
pomodoro.PausePomodoro() // Pause the timer
}
case "resume":
if pomodoro.IsPomodoroOngoing() && pomodoro.IsPomodoroPaused() {
pomodoro.ResumePomodoro() // Resume the timer
} }
go pomodoro.RunPomodoro(pomodoroConfig) // Start the timer with the list of clients
}
case "stop":
if pomodoro.IsPomodoroOngoing() {
pomodoro.ResetPomodoro() // Reset Pomodoro
}
case "pause":
if pomodoro.IsPomodoroOngoing() && !pomodoro.IsPomodoroPaused() {
pomodoro.PausePomodoro() // Pause the timer
}
case "resume":
if pomodoro.IsPomodoroOngoing() && pomodoro.IsPomodoroPaused() {
pomodoro.ResumePomodoro() // Resume the timer
} }
} }

View file

@ -8,8 +8,9 @@ import (
// ClientCommand represents a command from the client (start/stop). // ClientCommand represents a command from the client (start/stop).
type ClientCommand struct { type ClientCommand struct {
Command string `json:"command"` Command string `json:"command"` // comman send to the server
Config GoTomatoPomodoroConfig `json:"config"` Password string `json:"password"` // pomodoro control password
Config GoTomatoPomodoroConfig `json:"config"` // pomodoro config
} }
type Client struct { type Client struct {