feat: Add clients base URL
All checks were successful
/ pre-commit (push) Successful in 1m18s

- Add `clients_base_url` to define an alternative URL to download clients

- Rename `clients_directory` to `clients_base_directory` to download clients
  locally based on the version. If `show_version` is disabled and
  `clients_base_directory` are both defined, a redirection to a remote URL with
  the "latest" version is chosen in order to avoid to disclose the server
  version.

Fixes #43.

Signed-off-by: Julien Riou <julien@riou.xyz>
This commit is contained in:
Julien Riou 2025-10-10 12:52:27 +02:00
commit b35828d909
Signed by: jriou
GPG key ID: 9A099EDA51316854
4 changed files with 24 additions and 14 deletions

View file

@ -41,7 +41,8 @@ The file format is **JSON**:
* **tls_key_file** (string): Path to TLS key file to enable HTTPS * **tls_key_file** (string): Path to TLS key file to enable HTTPS
* **ace_directory** (string): Serve [Ace](hhttps://ace.c9.io/) assets from this local directory (ex: "./node_modules/ace-builds"). See **Dependencies** for details. * **ace_directory** (string): Serve [Ace](hhttps://ace.c9.io/) assets from this local directory (ex: "./node_modules/ace-builds"). See **Dependencies** for details.
* **bootstrap_directory** (string): Serve [Bootstrap](https://getbootstrap.com/) assets from this local directory (ex: "./node_modules/bootstrap/dist"). See **Dependencies** for details. * **bootstrap_directory** (string): Serve [Bootstrap](https://getbootstrap.com/) assets from this local directory (ex: "./node_modules/bootstrap/dist"). See **Dependencies** for details.
* **clients_directory** (string): Serve clients binaries from this local directory (ex: "./releases/1.2.0") * **clients_base_directory** (string): Serve clients binaries from this local base directory (ex: "./releases"). The version will be append to the directory. Ignored if `show_version` is disabled.
* **clients_base_url** (string): Define the base URL to download clients (default "https://git.riou.xyz/jriou/coller/releases/download"). The version (or "latest") will be append.
* **disable_editor** (bool): Disable Ace editor. * **disable_editor** (bool): Disable Ace editor.
The configuration file is not required but the service might not be exposed to the public. The configuration file is not required but the service might not be exposed to the public.

View file

@ -34,7 +34,8 @@ type Config struct {
AceDirectory string `json:"ace_directory"` AceDirectory string `json:"ace_directory"`
BootstrapDirectory string `json:"bootstrap_directory"` BootstrapDirectory string `json:"bootstrap_directory"`
DisableEditor bool `json:"disable_editor"` DisableEditor bool `json:"disable_editor"`
ClientsDirectory string `json:"clients_directory"` ClientsBaseURL string `json:"clients_base_url"`
ClientsBaseDirectory string `json:"clients_base_directory"`
} }
func NewConfig() *Config { func NewConfig() *Config {
@ -81,6 +82,7 @@ func NewConfig() *Config {
Language: "text", Language: "text",
EnableUploadFileButton: true, EnableUploadFileButton: true,
EnablePasswordProtection: true, EnablePasswordProtection: true,
ClientsBaseURL: "https://git.riou.xyz/jriou/coller/releases/download",
} }
} }

View file

@ -232,9 +232,10 @@ func (h *GetProtectedNoteHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque
} }
type ClientHandler struct { type ClientHandler struct {
logger *slog.Logger logger *slog.Logger
version string version string
directory string baseURL string
baseDirectory string
} }
func (h *ClientHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (h *ClientHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@ -249,14 +250,19 @@ func (h *ClientHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
version := h.version // No disclosure of the version running on the server
if version == "" { if h.version == "" {
version = "latest" http.Redirect(w, r, fmt.Sprintf("%s/%s/%s-%s-%s", h.baseURL, "latest", clientName, os, arch), http.StatusMovedPermanently)
return
} }
if h.directory != "" { if h.baseDirectory != "" {
http.ServeFile(w, r, h.directory+"/"+fmt.Sprintf("%s-%s-%s", clientName, os, arch)) // Serve file locally
// Example: ./releases/1.2.0/coller-linux-amd64
http.ServeFile(w, r, fmt.Sprintf("%s/%s/%s-%s-%s", h.baseDirectory, h.version, clientName, os, arch))
} else { } else {
http.Redirect(w, r, fmt.Sprintf("https://git.riou.xyz/jriou/coller/releases/download/%s/%s-%s-%s", version, clientName, os, arch), http.StatusMovedPermanently) // Redirect to a download link
// Example: https://git.riou.xyz/jriou/coller/releases/download/1.2.0/coller-linux-amd64
http.Redirect(w, r, fmt.Sprintf("%s/%s/%s-%s-%s", h.baseURL, h.version, clientName, os, arch), http.StatusMovedPermanently)
} }
} }

View file

@ -133,9 +133,10 @@ func (s *Server) Start() error {
r.Path("/clients.html").Handler(clientsHandler).Methods("GET") r.Path("/clients.html").Handler(clientsHandler).Methods("GET")
clientHandler := &ClientHandler{ clientHandler := &ClientHandler{
logger: s.logger, logger: s.logger,
version: p.Version, version: p.Version,
directory: s.config.ClientsDirectory, baseURL: s.config.ClientsBaseURL,
baseDirectory: s.config.ClientsBaseDirectory,
} }
r.Path("/clients/{os:[a-z]+}-{arch:[a-z0-9]+}/{clientName:[a-z]+}").Handler(clientHandler).Methods("GET") r.Path("/clients/{os:[a-z]+}-{arch:[a-z0-9]+}/{clientName:[a-z]+}").Handler(clientHandler).Methods("GET")