Documentation rework.
This commit is contained in:
@@ -1,291 +0,0 @@
|
|||||||
# Installation instructions
|
|
||||||
|
|
||||||
## Build the `galene` binary
|
|
||||||
|
|
||||||
Do:
|
|
||||||
|
|
||||||
CGO_ENABLED=0 go build -ldflags='-s -w'
|
|
||||||
|
|
||||||
On Windows, do
|
|
||||||
|
|
||||||
set CGO_ENABLED=0
|
|
||||||
go build -ldflags="-s -w"
|
|
||||||
|
|
||||||
## Set up a group
|
|
||||||
|
|
||||||
Set up a group called *test* by creating a file `groups/test.json`:
|
|
||||||
|
|
||||||
mkdir groups
|
|
||||||
vi groups/test.json
|
|
||||||
|
|
||||||
You may use the following definition:
|
|
||||||
|
|
||||||
{
|
|
||||||
"users":{
|
|
||||||
"admin": {"password": "1234", "permissions": "op"}
|
|
||||||
},
|
|
||||||
"wildcard-user": {
|
|
||||||
"password": {"type": "wildcard"},
|
|
||||||
"permissions": "present"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
See the README file for more details about defining groups.
|
|
||||||
|
|
||||||
|
|
||||||
## Optional: install libraries for background blur
|
|
||||||
|
|
||||||
Galene's client uses Google's MediaPipe library to implement background
|
|
||||||
blur. This library is optional, and if it is absent, Galene will
|
|
||||||
disable the menu entries for background blur.
|
|
||||||
|
|
||||||
Optionally install Google's MediaPipe library:
|
|
||||||
```
|
|
||||||
mkdir mediapipe
|
|
||||||
cd mediapipe
|
|
||||||
npm pack @mediapipe/tasks-vision
|
|
||||||
tar xzf mediapipe-tasks-vision-*.tgz
|
|
||||||
rm -f ../static/third-party/tasks-vision
|
|
||||||
mv package ../static/third-party/tasks-vision
|
|
||||||
cd ../static/third-party/tasks-vision
|
|
||||||
mkdir models
|
|
||||||
cd models
|
|
||||||
wget https://storage.googleapis.com/mediapipe-models/image_segmenter/selfie_segmenter/float16/latest/selfie_segmenter.tflite
|
|
||||||
cd ../../../../
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Test locally
|
|
||||||
|
|
||||||
./galene &
|
|
||||||
|
|
||||||
You should be able to access Galène at `https://localhost:8443`. Connect
|
|
||||||
to the group that you have just set up in two distinct browser windows,
|
|
||||||
then press *Ready* in one of the two; you should see a video in the other.
|
|
||||||
|
|
||||||
|
|
||||||
## Configure your server's firewall
|
|
||||||
|
|
||||||
If your server has a global IPv4 address and there is no firewall, there
|
|
||||||
is nothing to do.
|
|
||||||
|
|
||||||
If your server has a global IPv4 address, then the firewall must allow
|
|
||||||
traffic to and from:
|
|
||||||
|
|
||||||
* TCP port 8443 (or whatever is configured with the `-http` option); and
|
|
||||||
|
|
||||||
* TCP and UDP port 1194 (or whatever is configured with the `-turn` option).
|
|
||||||
|
|
||||||
For good performance, your firewall should allow incoming and outgoing
|
|
||||||
traffic from the UDP ports used for media transfer. By default, these are
|
|
||||||
all high-numbered (ephemeral) ports, but they can be restricted using one
|
|
||||||
of the following options:
|
|
||||||
|
|
||||||
* the `-udp-range port1-port2` option restricts the UDP ports to be in
|
|
||||||
the range from port1 to port2 inclusive; this should be a large range,
|
|
||||||
on the order of a few tens of thousands of ports;
|
|
||||||
|
|
||||||
* the `-udp-range port` option makes the server use just a single port,
|
|
||||||
and demultiplex the traffic in userspace.
|
|
||||||
|
|
||||||
If your server is behind NAT (which is not recommended), then the NAT must
|
|
||||||
forward, at the very least, port 8443 to your server. Ideally, you should
|
|
||||||
configure an external TURN server (see *ICE Servers* below) on a host that
|
|
||||||
is not behind NAT. If that is not possible, then you must use a NAT that
|
|
||||||
supports hairpinning, you must forward port 1194 in addition to port 8443,
|
|
||||||
and you will need to add add the option `-turn 203.0.113.1:1194` to
|
|
||||||
Galène's command line, where `203.0.113.1` is your NAT's external (global)
|
|
||||||
IPv4 address.
|
|
||||||
|
|
||||||
|
|
||||||
## Cross-compile for your server
|
|
||||||
|
|
||||||
This step is only required if your server runs a different OS or has
|
|
||||||
a different CPU than your build machine.
|
|
||||||
|
|
||||||
For a Linux server with an Intel or AMD CPU:
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags='-s -w'
|
|
||||||
|
|
||||||
For a Raspberry Pi 1:
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags='-s -w'
|
|
||||||
|
|
||||||
For a BeagleBone or a Raspberry Pi 2 or later:
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags='-s -w'
|
|
||||||
|
|
||||||
For a 64-bit ARM board (Olimex Olinuxino-A64, Pine64, etc.) or server:
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags='-s -w'
|
|
||||||
|
|
||||||
For a 32-bit MIPS board with no hardware floating point (WNDR3800, etc.):
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build -ldflags='-s -w'
|
|
||||||
|
|
||||||
|
|
||||||
## Deploy to your server
|
|
||||||
|
|
||||||
Set up a user *galene* on your server, then copy the `galene` binary, and
|
|
||||||
the directories `static`, `data` and `groups`:
|
|
||||||
|
|
||||||
rsync -a galene static data groups galene@server.example.org:
|
|
||||||
|
|
||||||
If you don't have a TLS certificate, Galène will generate a self-signed
|
|
||||||
certificate automatically (and print a warning to the logs). If you have
|
|
||||||
a certificate, install it in the files `data/cert.pem` and `data/key.pem`:
|
|
||||||
|
|
||||||
ssh galene@server.example.org
|
|
||||||
sudo cp /etc/letsencrypt/live/server.example.org/fullchain.pem data/cert.pem
|
|
||||||
sudo cp /etc/letsencrypt/live/server.example.org/privkey.pem data/key.pem
|
|
||||||
sudo chown galene:galene data/*.pem
|
|
||||||
sudo chmod go-rw data/key.pem
|
|
||||||
|
|
||||||
Now arrange to run the binary on the server. If you never reboot your
|
|
||||||
server, it might be as simple as
|
|
||||||
|
|
||||||
ssh galene@server.example.org
|
|
||||||
ulimit -n 65536
|
|
||||||
nohup ./galene &
|
|
||||||
|
|
||||||
If you are using *runit*, use a script like the following:
|
|
||||||
|
|
||||||
#!/bin/sh
|
|
||||||
exec 2>&1
|
|
||||||
cd ~galene
|
|
||||||
ulimit -n 65536
|
|
||||||
exec setuidgid galene ./galene
|
|
||||||
|
|
||||||
If you are using *systemd*:
|
|
||||||
|
|
||||||
[Unit]
|
|
||||||
Description=Galene
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
WorkingDirectory=/home/galene
|
|
||||||
User=galene
|
|
||||||
Group=galene
|
|
||||||
ExecStart=/home/galene/galene
|
|
||||||
LimitNOFILE=65536
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
|
|
||||||
|
|
||||||
# Running behind a reverse proxy
|
|
||||||
|
|
||||||
Galene is designed to be directly exposed to the Internet. In order to
|
|
||||||
run Galene behind a reverse proxy, you might need to make a number of
|
|
||||||
tweaks to your configuration.
|
|
||||||
|
|
||||||
First, you might need to inform Galene of the URL at which users connect
|
|
||||||
(the reverse proxy's URL) by adding an entry `proxyURL` to your
|
|
||||||
`data/config.json` file:
|
|
||||||
|
|
||||||
{
|
|
||||||
"proxyURL": "https://galene.example.org/"
|
|
||||||
}
|
|
||||||
|
|
||||||
Second, and depending on your proxy implementation, you might need to
|
|
||||||
request that the proxy pass WebSocket handshakes to the URL at `ws`; for
|
|
||||||
example, with Nginx, you will need to say something like the following:
|
|
||||||
|
|
||||||
location /ws {
|
|
||||||
proxy_pass ...;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "Upgrade";
|
|
||||||
}
|
|
||||||
|
|
||||||
Finally, in order to avoid TLS termination issues, you may want to run
|
|
||||||
Galene over plain HTTP instead of HTTPS by using the command-line flag
|
|
||||||
`-insecure`.
|
|
||||||
|
|
||||||
Note that even if you're using a reverse proxy, clients will attempt to
|
|
||||||
establish direct UDP flows with Galene and direct TCP connections to
|
|
||||||
Galene's TURN server; see the section on "Configuring your firewall"
|
|
||||||
above.
|
|
||||||
|
|
||||||
|
|
||||||
# Connectivity issues and ICE Servers
|
|
||||||
|
|
||||||
Most connectivity issues are due to an incorrect ICE configuration.
|
|
||||||
|
|
||||||
ICE is the NAT and firewall traversal protocol used by WebRTC. ICE can
|
|
||||||
make use of two kinds of servers to help with NAT traversal: STUN servers,
|
|
||||||
that help punching holes in well-behaved NATs, and TURN servers, that
|
|
||||||
serve as relays for traffic. TURN is a superset of STUN: no STUN server
|
|
||||||
is necessary if one or more TURN servers are available.
|
|
||||||
|
|
||||||
Galène includes an IPv4-only TURN server, which is controlled by the
|
|
||||||
`-turn` command-line option. It has the following behaviour:
|
|
||||||
|
|
||||||
* if its value is set to the empty string `""`, then the built-in server
|
|
||||||
is disabled; in this case, the file `data/ice-servers.json` configures
|
|
||||||
an external TURN server;
|
|
||||||
|
|
||||||
* if its value is a colon followed with a port number, for example
|
|
||||||
`:1194`, then the TURN server will listen on all public IPv4 addresses
|
|
||||||
of the local host, over UDP and TCP; this is the recommended value if
|
|
||||||
the server is not behind NAT, and the firewall allows incoming
|
|
||||||
connections to port 1194;
|
|
||||||
|
|
||||||
* if the value of this option is a socket address, such as
|
|
||||||
`203.0.113.1:1194`, then the TURN server will listen on all addresses
|
|
||||||
of the local host but assume that the address seen by the clients is
|
|
||||||
the one given in the option; this is useful when running behind NAT
|
|
||||||
with port forwarding set up.
|
|
||||||
|
|
||||||
* the default value is `auto`, which behaves like `:1194` if there is no
|
|
||||||
`data/ice-servers.json` file, and like `""` otherwise.
|
|
||||||
|
|
||||||
If the server is not accessible from the Internet, e.g. because of NAT or
|
|
||||||
because it is behind a restrictive firewall, then you should configure
|
|
||||||
a TURN server that runs on a host that is accessible by both Galène and
|
|
||||||
the clients. Disable the built-in TURN server (`-turn ""` or the default
|
|
||||||
`-turn auto`), and provide a working ICE configuration in the file
|
|
||||||
`data/ice-servers.json`. In the case of a single STUN server, it should
|
|
||||||
look like this:
|
|
||||||
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"urls": [
|
|
||||||
"stun:stun.example.org"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
In the case of s single TURN server, the `ice-servers.json` file should
|
|
||||||
look like this:
|
|
||||||
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"urls": [
|
|
||||||
"turn:turn.example.org:443",
|
|
||||||
"turn:turn.example.org:443?transport=tcp"
|
|
||||||
],
|
|
||||||
"username": "galene",
|
|
||||||
"credential": "secret"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
It is more secure to use coturn's `use-auth-secret` option. If you do
|
|
||||||
that, then the `ice-servers.json` file should look like this:
|
|
||||||
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"urls": [
|
|
||||||
"turn:turn.example.com:443",
|
|
||||||
"turn:turn.example.com:443?transport=tcp"
|
|
||||||
],
|
|
||||||
"username": "galene",
|
|
||||||
"credential": "secret",
|
|
||||||
"credentialType": "hmac-sha1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
For redundancy, you may set up multiple TURN servers, and ICE will use the
|
|
||||||
first one that works. If an `ice-servers.json` file is present and
|
|
||||||
Galène's built-in TURN server is enabled, then the external server will be
|
|
||||||
used in preference to the built-in server.
|
|
||||||
@@ -1,408 +0,0 @@
|
|||||||
Galene is a videoconferencing server that is easy to deploy and requires
|
|
||||||
moderate server resources. It is described at <https://galene.org>.
|
|
||||||
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
|
|
||||||
Quick start:
|
|
||||||
|
|
||||||
git clone https://github.com/jech/galene
|
|
||||||
cd galene
|
|
||||||
CGO_ENABLED=0 go build -ldflags='-s -w'
|
|
||||||
mkdir groups
|
|
||||||
echo '{"users": {"bob": {"password":"1234", "permissions":"op"}}}' > \
|
|
||||||
groups/example.json
|
|
||||||
./galene &
|
|
||||||
|
|
||||||
Point your browser at <https://localhost:8443/group/example/>, ignore the
|
|
||||||
unknown certificate warning, and log in with username "bob" and password
|
|
||||||
"1234".
|
|
||||||
|
|
||||||
See the file INSTALL in this directory for full installation instructions.
|
|
||||||
|
|
||||||
|
|
||||||
# Usage
|
|
||||||
|
|
||||||
## Locations
|
|
||||||
|
|
||||||
There is a landing page at the root of the server. It contains a form
|
|
||||||
for typing the name of a group, and a clickable list of public groups.
|
|
||||||
|
|
||||||
Groups are available under `/group/groupname/`. You may share this URL
|
|
||||||
with others, there is no need to go through the landing page.
|
|
||||||
|
|
||||||
Recordings can be accessed under `/recordings/groupname/`. This is only
|
|
||||||
available to the group operator.
|
|
||||||
|
|
||||||
Some statistics are available under `/stats.json`, with a human-readable
|
|
||||||
version at `/stats.html`. This is only available to the server administrator.
|
|
||||||
|
|
||||||
|
|
||||||
## Main interface
|
|
||||||
|
|
||||||
After logging in, the user is confronted with the main interface.
|
|
||||||
|
|
||||||
### Buttons
|
|
||||||
|
|
||||||
There are up to three buttons at the top. The *Enable*/*Disable* button
|
|
||||||
enables either or both the camera and the microphone (depending on the
|
|
||||||
options set in the side menu, see below). The *Mute* button mutes or
|
|
||||||
unmutes the microphone. The *Share Screen* button shares the screen or
|
|
||||||
a window.
|
|
||||||
|
|
||||||
### Side menu
|
|
||||||
|
|
||||||
There is a menu on the right of the user interface. This allows choosing
|
|
||||||
the camera and microphone and setting the video throughput. The
|
|
||||||
*Blackboard mode* checkbox increases resolution and sacrifices framerate
|
|
||||||
in favour of image quality. The *Play local file* dialog allows streaming
|
|
||||||
a video from a local file.
|
|
||||||
|
|
||||||
### User list
|
|
||||||
|
|
||||||
There is a user list on the left. Clicking on a user opens a menu with
|
|
||||||
actions that can be applied to that user. Clicking on ones own username
|
|
||||||
opens a menu with actions that are global to the group.
|
|
||||||
|
|
||||||
### Chat pane
|
|
||||||
|
|
||||||
Double-clicking on a message opens a contextual menu.
|
|
||||||
|
|
||||||
### Text box
|
|
||||||
|
|
||||||
Typing a string in the text box at the bottom of the chat pane sends
|
|
||||||
a broadcast message to all of the users in the group.
|
|
||||||
|
|
||||||
Typing a line starting with a slash `/` in the text box causes a command
|
|
||||||
to be sent to the server. Type `/help` to get the list of available
|
|
||||||
commands; the output depends on whether you are an operator or not.
|
|
||||||
|
|
||||||
|
|
||||||
# The global configuration file
|
|
||||||
|
|
||||||
The server may be configured in the JSON file `data/config.json`. This
|
|
||||||
file may look as follows:
|
|
||||||
|
|
||||||
{
|
|
||||||
"users":{"root": {"password":"secret", "permissions": "admin"}},
|
|
||||||
"canonicalHost": "galene.example.org"
|
|
||||||
}
|
|
||||||
|
|
||||||
or, better, with a hashed password:
|
|
||||||
|
|
||||||
{
|
|
||||||
"users": {
|
|
||||||
"root": {
|
|
||||||
"password":{"type":"bcrypt","key":"$2a$10$bTWW..."},
|
|
||||||
"permissions": "admin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"canonicalHost": "galene.example.org"
|
|
||||||
}
|
|
||||||
|
|
||||||
The fields are as follows:
|
|
||||||
|
|
||||||
- `users` defines the users allowed to administer the server, and has the
|
|
||||||
same syntax as user definitions in groups (see below), except that the
|
|
||||||
only meaningful permission is `"admin"`;
|
|
||||||
|
|
||||||
- `writableGroups`: if true, then the API can modify group description
|
|
||||||
files; by default, group files are treated as read-only;
|
|
||||||
|
|
||||||
- `allowOrigin` is an array that contains the list of HTTP origins that
|
|
||||||
are allowed to access the server.
|
|
||||||
|
|
||||||
- `allowAdminOrigin` is like `allowOrigin`, but applies to the
|
|
||||||
administrative interface.
|
|
||||||
|
|
||||||
- `proxyURL`: if running behind a reverse proxy, this specifies the root
|
|
||||||
URL that will be visible outside the proxy.
|
|
||||||
|
|
||||||
- `canonicalHost`: the canonical name of the host running the server;
|
|
||||||
this will cause clients to be redirected if they use a different
|
|
||||||
hostname to access the server.
|
|
||||||
|
|
||||||
|
|
||||||
# Group definitions
|
|
||||||
|
|
||||||
Groups are defined by files in the `./groups` directory (this may be
|
|
||||||
configured by the `-groups` command-line option, try `./galene -help`).
|
|
||||||
The definition for the group called *groupname* is in the file
|
|
||||||
`groups/groupname.json`; it does not contain the group name, which makes
|
|
||||||
it easy to copy or link group definitions. You may use subdirectories:
|
|
||||||
a file `groups/teaching/networking.json` defines a group called
|
|
||||||
*teaching/networking*.
|
|
||||||
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
A typical group definition file looks like this:
|
|
||||||
|
|
||||||
{
|
|
||||||
"users":{
|
|
||||||
"jch": {"password":"1234", "permissions": "op"}
|
|
||||||
},
|
|
||||||
"allow-recording": true,
|
|
||||||
"auto-subgroups": true
|
|
||||||
}
|
|
||||||
|
|
||||||
This defines a group with the operator username *jch* and password *1234*.
|
|
||||||
The `allow-recording` entry says that the operator is allowed to record
|
|
||||||
videos to disk, and the `auto-subgroups` entry says that subgroups will be
|
|
||||||
created automatically. This particular group does not allow password
|
|
||||||
login for ordinary users, and is suitable if you use invitations (see
|
|
||||||
*Stateful Tokens* below) for ordinary users.
|
|
||||||
|
|
||||||
In order to allow password login for ordinary users, add password entries
|
|
||||||
with the permission `present`:
|
|
||||||
|
|
||||||
{
|
|
||||||
"users":{
|
|
||||||
"jch": {"password": "1234", "permissions": "op"},
|
|
||||||
"john": {"password": "secret", "permissions": "present"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
If the group is to be publicly accessible, you may allow logins with any
|
|
||||||
username using the `wildcard-user` entry::
|
|
||||||
|
|
||||||
{
|
|
||||||
"users":{
|
|
||||||
"jch": {"password":"1234", "permissions": "op"}
|
|
||||||
},
|
|
||||||
"wildcard-user": {"password": "1234", "permissions": "present"},
|
|
||||||
"public": true
|
|
||||||
}
|
|
||||||
|
|
||||||
If you want to allow users to use any password, use a wildcard password:
|
|
||||||
|
|
||||||
{
|
|
||||||
"users":{
|
|
||||||
"jch": {"password":"1234", "permissions": "op"}
|
|
||||||
},
|
|
||||||
"wildcard-user":
|
|
||||||
{"password": {"type": "wildcard"}, "permissions": "present"},
|
|
||||||
"public": true
|
|
||||||
}
|
|
||||||
|
|
||||||
## Reference
|
|
||||||
|
|
||||||
Every group definition file contains a single JSON directory (a list of
|
|
||||||
entries between `{` and `}`). All fields are optional, but unless you
|
|
||||||
specify at least one user definition (`op`, `presenter`, or `other`),
|
|
||||||
nobody will be able to join the group. The following fields are allowed:
|
|
||||||
|
|
||||||
- `users`: is a dictionary that maps user names to dictionaries with
|
|
||||||
entries `password` and `permissions`; see below for a description of
|
|
||||||
possible permissions;
|
|
||||||
|
|
||||||
- `wildcard-user` is a dictionaries with entries `password` and `permissions`
|
|
||||||
that will be used for usernames with no matching entry in the `users`
|
|
||||||
dictionary;
|
|
||||||
|
|
||||||
- `authKeys`, `authServer` and `authPortal`: see *Authorisation* below;
|
|
||||||
|
|
||||||
- `public`: if true, then the group is listed on the landing page;
|
|
||||||
|
|
||||||
- `displayName`: a human-friendly version of the group name;
|
|
||||||
|
|
||||||
- `description`: a human-readable description of the group; this is
|
|
||||||
displayed on the landing page for public groups;
|
|
||||||
|
|
||||||
- `contact`: a human-readable contact for this group, such as an e-mail
|
|
||||||
address, ignored by the server;
|
|
||||||
|
|
||||||
- `comment`: a human-readable string, ignored by the server;
|
|
||||||
|
|
||||||
- `max-clients`: the maximum number of clients that may join the group at
|
|
||||||
a time;
|
|
||||||
|
|
||||||
- `max-history-age`: the time, in seconds, during which chat history is
|
|
||||||
kept (default 14400, i.e. 4 hours);
|
|
||||||
|
|
||||||
- `not-before` and `expires`: the times (in ISO 8601 or RFC 3339 format)
|
|
||||||
between which joining the group is allowed;
|
|
||||||
|
|
||||||
- `allow-recording`: if true, then recording is allowed in this group;
|
|
||||||
|
|
||||||
- `unrestricted-tokens`: if true, then ordinary users (without the "op"
|
|
||||||
privilege) are allowed to create tokens;
|
|
||||||
|
|
||||||
- `allow-anonymous`: if true, then users may connect with an empty username;
|
|
||||||
|
|
||||||
- `auto-subgroups`: if true, then subgroups of the form `group/subgroup`
|
|
||||||
are automatically created when first accessed;
|
|
||||||
|
|
||||||
- `autolock`: if true, the group will start locked and become locked
|
|
||||||
whenever there are no clients with operator privileges;
|
|
||||||
|
|
||||||
- `autokick`: if true, all clients will be kicked out whenever there are
|
|
||||||
no clients with operator privileges; this is not recommended, prefer
|
|
||||||
the `autolock` option instead;
|
|
||||||
|
|
||||||
- `redirect`: if set, then attempts to join the group will be redirected
|
|
||||||
to the given URL; most other fields are ignored in this case;
|
|
||||||
|
|
||||||
- `codecs`: this is a list of codecs allowed in this group. The default
|
|
||||||
is `["vp8", "opus"]`.
|
|
||||||
|
|
||||||
The value of the `permissions` entry in a user definition can either be an
|
|
||||||
array of individual permissions, as carried by the protocol, or one of
|
|
||||||
the following strings:
|
|
||||||
|
|
||||||
- `op`, a group operator with all rights except administering the group;
|
|
||||||
- `present`, an ordinary user with the right to publish audio and video
|
|
||||||
streams and send chat messages;
|
|
||||||
- `message`, a user with the right to send chat messages;
|
|
||||||
- `observe`, a user that receives media streams and chat messages, but
|
|
||||||
is not allowed to send them;
|
|
||||||
- `caption`, a user with the right to display captions (only);
|
|
||||||
- `admin`, a user with the right to administer the group (only).
|
|
||||||
|
|
||||||
Supported video codecs include:
|
|
||||||
|
|
||||||
- `"vp8"` (compatible with all supported browsers);
|
|
||||||
- `"vp9"` (better video quality, but incompatible with Safari; buggy in
|
|
||||||
Firefox);
|
|
||||||
- `"av1"` (even better video quality, only supported by some browsers,
|
|
||||||
recording is not supported, SVC is not supported);
|
|
||||||
- `"h264"` (incompatible with Debian and with some older Android devices,
|
|
||||||
SVC is not supported).
|
|
||||||
|
|
||||||
Supported audio codecs include `"opus"`, `"g722"`, `"pcmu"` and `"pcma"`.
|
|
||||||
Only Opus can be recorded to disk. There is no good reason to use
|
|
||||||
anything except Opus.
|
|
||||||
|
|
||||||
|
|
||||||
## Client Authorisation
|
|
||||||
|
|
||||||
Galene implements three authorisation methods: a simple username/password
|
|
||||||
authorisation scheme, a scheme using stateful tokens and a mechanism based
|
|
||||||
on cryptographic tokens that are generated by an external server. The
|
|
||||||
former two mechanism are intended to be used in standalone installations,
|
|
||||||
while the server-based mechanism is designed to allow easy integration
|
|
||||||
with an existing authorisation infrastructure (such as LDAP, OAuth2, or
|
|
||||||
even Unix passwords).
|
|
||||||
|
|
||||||
### Password authorisation
|
|
||||||
|
|
||||||
When password authorisation is used, authorised usernames and password are
|
|
||||||
defined directly in the group configuration file, in the `users` and
|
|
||||||
`wildcard-user` entries. The `users` entry is a dictionary that maps user
|
|
||||||
names to user descriptions; the `wildcard-user` is a user description
|
|
||||||
that is used with usernames that don't appear in `users`.
|
|
||||||
|
|
||||||
Every user description is a dictionary with fields `password` and
|
|
||||||
`permissions`. The `password` field may be a literal password string, or
|
|
||||||
a dictionary describing a hashed password or a wildcard. The
|
|
||||||
`permissions` field should be one of `op`, `present`, `message` or
|
|
||||||
`observe`. (An array of Galene's internal permissions is also allowed,
|
|
||||||
but this is not recommended, since internal permissions may vary from
|
|
||||||
version to version).
|
|
||||||
|
|
||||||
For example, the entry
|
|
||||||
|
|
||||||
"users": {"jch": {"password": "1234", "permissions": "op"}}
|
|
||||||
|
|
||||||
specifies that user "jch" may login as operator with password "1234", while
|
|
||||||
|
|
||||||
"wildcard-user": {"password": "1234", "permissions": "present"}
|
|
||||||
|
|
||||||
allows any username with password *1234*. Finally,
|
|
||||||
|
|
||||||
"wildcard-user":
|
|
||||||
{"password": {"type": "wildcard"}, "permissions": "present"}
|
|
||||||
|
|
||||||
allows any username with any password.
|
|
||||||
|
|
||||||
|
|
||||||
### Hashed passwords
|
|
||||||
|
|
||||||
If you don't wish to store cleartext passwords on the server, you may
|
|
||||||
generate hashed passwords with the `galenectl` utility. A user entry with
|
|
||||||
a hashed password looks like this:
|
|
||||||
|
|
||||||
"users": {
|
|
||||||
"jch": {
|
|
||||||
"password": {
|
|
||||||
"type": "pbkdf2",
|
|
||||||
"hash": "sha-256",
|
|
||||||
"key": "f591c35604e6aef572851d9c3543c812566b032b6dc083c81edd15cc24449913",
|
|
||||||
"salt": "92bff2ace56fe38f",
|
|
||||||
"iterations": 4096
|
|
||||||
},
|
|
||||||
"permissions": "op"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
### Stateful tokens
|
|
||||||
|
|
||||||
Stateful tokens allow to temporarily grant access to a user. In order to
|
|
||||||
generate a stateful token, the group operator types
|
|
||||||
|
|
||||||
/invite user period
|
|
||||||
|
|
||||||
where `user` is the username granted to the temporary user, and `period`
|
|
||||||
is the time period for which the token will be valid (for example `2d`
|
|
||||||
meaning 2 days). The server replies with a link, valid the given time
|
|
||||||
period, that may be sent to the temporary user for example by e-mail.
|
|
||||||
|
|
||||||
Tokens may also be granted without imposing a specific username:
|
|
||||||
|
|
||||||
/invite '' 2d
|
|
||||||
|
|
||||||
Stateful tokens are revokable (use the `/revoke` command) and their
|
|
||||||
lifetime may be extended (use the `/reinvite` command).
|
|
||||||
|
|
||||||
|
|
||||||
### Authorisation servers
|
|
||||||
|
|
||||||
Galene is able to delegate authorisation decisions to an external
|
|
||||||
authorisation server. This makes it possible to integrate Galene with an
|
|
||||||
existing authentication and authorisation infrastructure, such as LDAP,
|
|
||||||
OAuth2 or even Unix passwords.
|
|
||||||
|
|
||||||
When an authorisation server is used, the group configuration file
|
|
||||||
specifies one or more public keys in JWK format (with the restriction that
|
|
||||||
the "alg" key must be specified). In addition, it may specify either an
|
|
||||||
authorisation server or an authorisation portal.
|
|
||||||
|
|
||||||
{
|
|
||||||
"authKeys": [{
|
|
||||||
"kty": "oct",
|
|
||||||
"alg": "HS256",
|
|
||||||
"k": "MYz3IfCq4Yq-UmPdNqWEOdPl4C_m9imHHs9uveDUJGQ",
|
|
||||||
}, {
|
|
||||||
"kty": "EC",
|
|
||||||
"alg": "ES256",
|
|
||||||
"crv": "P-256",
|
|
||||||
"x": "dElK9qBNyCpRXdvJsn4GdjrFzScSzpkz_I0JhKbYC88",
|
|
||||||
"y": "pBhVb37haKvwEoleoW3qxnT4y5bK35_RTP7_RmFKR6Q",
|
|
||||||
}]
|
|
||||||
"authServer": "https://auth.example.org",
|
|
||||||
}
|
|
||||||
|
|
||||||
If multiple keys are provided, then they will all be tried in turn, unless
|
|
||||||
the token includes the "kid" header field, in which case only the
|
|
||||||
specified key will be used.
|
|
||||||
|
|
||||||
If an authorisation server is specified, then the default client, after it
|
|
||||||
prompts for a password, will request a token from the authorisation server
|
|
||||||
and will join the group using token authentication. The password is never
|
|
||||||
communicated to the server.
|
|
||||||
|
|
||||||
If an authorisation portal is specified, then the default client will
|
|
||||||
redirect initial client connections to the authorisation portal. The
|
|
||||||
authorisation portal is expected to authorise the client and then redirect
|
|
||||||
it to Galene with the `username` and `token` query parameters set.
|
|
||||||
|
|
||||||
|
|
||||||
# Further information
|
|
||||||
|
|
||||||
Galène's web page is at <https://galene.org>.
|
|
||||||
|
|
||||||
Answers to common questions and issues are at <https://galene.org/faq.html>.
|
|
||||||
|
|
||||||
|
|
||||||
-- Juliusz Chroboczek <https://www.irif.fr/~jch/>
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# The Galene videoconferencing system
|
||||||
|
|
||||||
|
Galene is a fully-features videoconferencing system that is easy to deploy
|
||||||
|
and requires very moderate server resources. It is described at
|
||||||
|
<https://galene.org>.
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/jech/galene
|
||||||
|
cd galene
|
||||||
|
CGO_ENABLED=0 go build -ldflags='-s -w'
|
||||||
|
mkdir groups
|
||||||
|
echo '{"users": {"vimes": {"password":"sybil", "permissions":"op"}}}' > groups/night-watch.json
|
||||||
|
./galene &
|
||||||
|
```
|
||||||
|
|
||||||
|
Point your browser at <https://localhost:8443/group/night-watch/>, ignore
|
||||||
|
the unknown certificate warning, and log in with username *vimes* and
|
||||||
|
password *sybil*.
|
||||||
|
|
||||||
|
For full installation instructions, please see the file [galene-install.md][1]
|
||||||
|
in this directory.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
* [galene-install.md][1]: full installation instructions
|
||||||
|
* [galene.md][2]: usage and administration;
|
||||||
|
* [galene-client.md][3]: writing clients;
|
||||||
|
* [galene-protocol.md][4]: the client protocol;
|
||||||
|
* [galene-api.md][4]: Galene's administrative API.
|
||||||
|
|
||||||
|
## Further information
|
||||||
|
|
||||||
|
Galène's web page is at <https://galene.org>.
|
||||||
|
|
||||||
|
Answers to common questions and issues are at <https://galene.org/faq.html>.
|
||||||
|
|
||||||
|
|
||||||
|
-- Juliusz Chroboczek <https://www.irif.fr/~jch/>
|
||||||
|
|
||||||
|
[1]: <galene-install.md>
|
||||||
|
[2]: <galene.md>
|
||||||
|
[3]: <galene-client.md>
|
||||||
|
[4]: <galene-protocol.md>
|
||||||
@@ -0,0 +1,366 @@
|
|||||||
|
# Galene installation instructions
|
||||||
|
|
||||||
|
## Basic installation
|
||||||
|
|
||||||
|
### Build the Galene binary
|
||||||
|
|
||||||
|
Say:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
CGO_ENABLED=0 go build -ldflags='-s -w'
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows, say:
|
||||||
|
|
||||||
|
```dosbat
|
||||||
|
set CGO_ENABLED=0
|
||||||
|
go build -ldflags="-s -w"
|
||||||
|
```
|
||||||
|
|
||||||
|
If your server has a different architecture than the machine on which you
|
||||||
|
are building, set the `GOOS` and `GOARCH` environment variables. For
|
||||||
|
example, in order to compile for a 64-bit ARM system (a Raspberry Pi or an
|
||||||
|
Olimex board, for example), you would say:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags='-s -w'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Optional: install libraries for background blur
|
||||||
|
|
||||||
|
Galene's client uses Google's MediaPipe library to implement background
|
||||||
|
blur. This library is optional, and if it is absent, Galene will
|
||||||
|
disable the menu entries for background blur.
|
||||||
|
|
||||||
|
Optionally install Google's MediaPipe library:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir mediapipe
|
||||||
|
cd mediapipe
|
||||||
|
npm pack @mediapipe/tasks-vision
|
||||||
|
tar xzf mediapipe-tasks-vision-*.tgz
|
||||||
|
rm -f ../static/third-party/tasks-vision
|
||||||
|
mv package ../static/third-party/tasks-vision
|
||||||
|
cd ../static/third-party/tasks-vision
|
||||||
|
mkdir models
|
||||||
|
cd models
|
||||||
|
wget https://storage.googleapis.com/mediapipe-models/image_segmenter/selfie_segmenter/float16/latest/selfie_segmenter.tflite
|
||||||
|
cd ../../../../
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deploy to your server
|
||||||
|
|
||||||
|
The following instructions assume that your server is called
|
||||||
|
`galene.example.org` and that you have already created a dedicated user
|
||||||
|
called `galene`.
|
||||||
|
|
||||||
|
First, create an empty directory called `groups`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir groups
|
||||||
|
```
|
||||||
|
|
||||||
|
Now copy the `galene` binary, and the directories `static`, `data` and
|
||||||
|
`groups` to the server:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
rsync -a galene static data groups galene@galene.example.org:
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don't have a TLS certificate, Galène will generate a self-signed
|
||||||
|
certificate (and print a warning to the logs). If you have a certificate,
|
||||||
|
install it in the files `data/cert.pem` and `data/key.pem`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ssh galene@galene.example.org
|
||||||
|
sudo cp /etc/letsencrypt/live/galene.example.org/fullchain.pem data/cert.pem
|
||||||
|
sudo cp /etc/letsencrypt/live/galene.example.org/privkey.pem data/key.pem
|
||||||
|
sudo chown galene:galene data/*.pem
|
||||||
|
chmod go-rw data/key.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
Since certificates are regularly rotated, this should be done in a monthly
|
||||||
|
cron job (or a *SystemD* timer unit, if you're feeling particularly kinky).
|
||||||
|
|
||||||
|
### Run Galene on the server
|
||||||
|
|
||||||
|
Arrange to run the binary on the server. If you never reboot your server,
|
||||||
|
just do:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ssh galene@galene.example.org
|
||||||
|
ulimit -n 65536
|
||||||
|
nohup ./galene &
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using *runit*, use a script like the following:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
#!/bin/sh
|
||||||
|
exec 2>&1
|
||||||
|
cd ~galene
|
||||||
|
ulimit -n 65536
|
||||||
|
exec setuidgid galene ./galene
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using *SystemD*, put the following in
|
||||||
|
`/etc/systemd/system/galene.service`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Unit]
|
||||||
|
Description=Galene
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
WorkingDirectory=/home/galene
|
||||||
|
User=galene
|
||||||
|
Group=galene
|
||||||
|
ExecStart=/home/galene/galene
|
||||||
|
LimitNOFILE=65536
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
### Set up galenectl
|
||||||
|
|
||||||
|
There are two ways to administer a Galene instance: by manually editing
|
||||||
|
JSON files on the server, or by using the `galenectl` utility.
|
||||||
|
The `galenectl` utility is recommended, since it avoids issues with
|
||||||
|
concurrent modifications and is less error-prone than the alternative.
|
||||||
|
|
||||||
|
Build the `galenectl` utility, and copy it somewhere on your path:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd galenectl
|
||||||
|
go build -ldflags='-s -w'
|
||||||
|
sudo cp galenectl /usr/local/bin
|
||||||
|
```
|
||||||
|
|
||||||
|
Now create an administrator password, and set up galenectl:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl -admin-username admin initial-setup
|
||||||
|
```
|
||||||
|
|
||||||
|
This command creates two files: `galenectl.conf` and `config.json`. The
|
||||||
|
former is already at the right place, the latter must be copied to the
|
||||||
|
server's `data/` directory:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
rsync config.json galene@galene.example.org:data/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Group setup
|
||||||
|
|
||||||
|
Create a group:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl create-group -group city-watch
|
||||||
|
```
|
||||||
|
|
||||||
|
If you didn't install a TLS certificate above, you will need to run
|
||||||
|
`galenectl` with the flag `-insecure`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl -insecure create-group -group city-watch
|
||||||
|
```
|
||||||
|
|
||||||
|
Create an "op", a user with group moderation privileges:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl create-user -group city-watch -user vimes -permissions op
|
||||||
|
```
|
||||||
|
|
||||||
|
Set the new user's password:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl set-password -group city-watch -user vimes
|
||||||
|
```
|
||||||
|
|
||||||
|
You should now be able to test your Galene installation by pointing a web
|
||||||
|
browser at <https://galene.example.org:8443/group/testing/>.
|
||||||
|
|
||||||
|
Create an ordinary user:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl create-user -group city-watch -user fred
|
||||||
|
galenectl set-password -group city-watch -user fred
|
||||||
|
```
|
||||||
|
|
||||||
|
Check the results:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl list-groups
|
||||||
|
galenectl list-users -l -group city-watch
|
||||||
|
```
|
||||||
|
|
||||||
|
Type `galenectl -help`, `galenectl create-group -help`, etc. for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
## Advanced configuration
|
||||||
|
|
||||||
|
Galene is designed to be exposed directly to the internet. If your server
|
||||||
|
is behind a firewall or NAT router, some extra configuration is necessary.
|
||||||
|
|
||||||
|
### Running behind a firewall
|
||||||
|
|
||||||
|
If your server is behind a firewall but has a global IPv4 address (it is
|
||||||
|
not behind NAT), then, at the very minimum, the firewall must allow
|
||||||
|
incoming connections to:
|
||||||
|
|
||||||
|
* TCP port 8443 (or whatever is configured with the `-http` option); and
|
||||||
|
|
||||||
|
* TCP and UDP port 1194 (or whatever is configured with the `-turn` option).
|
||||||
|
|
||||||
|
For good performance, your firewall should allow incoming and outgoing
|
||||||
|
traffic from the UDP ports used for media transfer. By default, these are
|
||||||
|
all high-numbered (ephemeral) ports, but they can be restricted using one
|
||||||
|
of the following options:
|
||||||
|
|
||||||
|
* the `-udp-range port1-port2` option restricts the UDP ports to be in
|
||||||
|
the range from port1 to port2 inclusive; this should be a large range,
|
||||||
|
on the order of a few tens of thousands of ports;
|
||||||
|
|
||||||
|
* the `-udp-range port` option makes the server use just a single port,
|
||||||
|
and demultiplex the traffic in userspace.
|
||||||
|
|
||||||
|
At the time of writing, this mechanism is not quite complete, and you will
|
||||||
|
see Galene attempting to use other ports. Unless you see connection
|
||||||
|
failures, this is nothing to worry about.
|
||||||
|
|
||||||
|
### Running behind NAT
|
||||||
|
|
||||||
|
If your server is behind NAT, then currently the only option is to use
|
||||||
|
a STUN, or, preferably, TURN server on a separate host, one that is not
|
||||||
|
behind NAT. See Section "Connectivity issues and ICE servers" below.
|
||||||
|
|
||||||
|
Galene has some support for running behind NAT without a helpful server,
|
||||||
|
but this has not been exhaustively tested. Please see the section
|
||||||
|
"Connectivity issues and ICE server" below.
|
||||||
|
|
||||||
|
### Running behind a reverse proxy
|
||||||
|
|
||||||
|
Galene is designed to be directly exposed to the Internet. In order to
|
||||||
|
run Galene behind a reverse proxy, you might need to make a number of
|
||||||
|
tweaks to your configuration.
|
||||||
|
|
||||||
|
First, you might need to inform Galene of the URL at which users connect
|
||||||
|
(the reverse proxy's URL) by adding an entry `proxyURL` to your
|
||||||
|
`data/config.json` file:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"proxyURL": "https://galene.example.org/"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Second, and depending on your proxy implementation, you might need to
|
||||||
|
request that the proxy pass WebSocket handshakes to the URL at `ws`; for
|
||||||
|
example, with Nginx, you will need to say something like the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
location /ws {
|
||||||
|
proxy_pass ...;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "Upgrade";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, in order to avoid TLS termination issues, you may want to run
|
||||||
|
Galene over plain HTTP instead of HTTPS by using the command-line flag
|
||||||
|
`-insecure`.
|
||||||
|
|
||||||
|
Note that even if you're using a reverse proxy, clients will attempt to
|
||||||
|
establish direct UDP flows with Galene and direct TCP connections to
|
||||||
|
Galene's TURN server; see the section on "Configuring your firewall"
|
||||||
|
above.
|
||||||
|
|
||||||
|
## Connectivity issues and ICE servers
|
||||||
|
|
||||||
|
Most connectivity issues are due to an incorrect ICE configuration.
|
||||||
|
|
||||||
|
ICE is the NAT and firewall traversal protocol used by WebRTC. ICE can
|
||||||
|
make use of two kinds of servers to help with NAT traversal: STUN servers,
|
||||||
|
that help punching holes in well-behaved NATs, and TURN servers, that
|
||||||
|
serve as relays for traffic. TURN is a superset of STUN: no STUN server
|
||||||
|
is necessary if one or more TURN servers are available.
|
||||||
|
|
||||||
|
Galène includes an IPv4-only TURN server, which is controlled by the
|
||||||
|
`-turn` command-line option. It has the following behaviour:
|
||||||
|
|
||||||
|
* if its value is set to the empty string `""`, then the built-in server
|
||||||
|
is disabled; in this case, the file `data/ice-servers.json` configures
|
||||||
|
an external TURN server;
|
||||||
|
|
||||||
|
* if its value is a colon followed with a port number, for example
|
||||||
|
`:1194`, then the TURN server will listen on all public IPv4 addresses
|
||||||
|
of the local host, over UDP and TCP; this is the recommended value if
|
||||||
|
the server is not behind NAT, and the firewall allows incoming
|
||||||
|
connections to the TURN port.
|
||||||
|
|
||||||
|
* if the value of this option is a socket address, such as
|
||||||
|
`203.0.113.1:1194`, then the TURN server will listen on all addresses
|
||||||
|
of the local host but assume that the address seen by the clients is
|
||||||
|
the one given in the option; this may be useful when running behind NAT
|
||||||
|
with port forwarding set up.
|
||||||
|
|
||||||
|
* the default value is `auto`, which behaves like `:1194` if there is no
|
||||||
|
`data/ice-servers.json` file, and like `""` otherwise.
|
||||||
|
|
||||||
|
If the server is not accessible from the Internet, e.g. because of NAT or
|
||||||
|
because it is behind a restrictive firewall, then you should configure
|
||||||
|
a TURN server that runs on a host that is accessible by both Galène and
|
||||||
|
the clients. Disable the built-in TURN server (`-turn ""` or the default
|
||||||
|
`-turn auto`), and provide a working ICE configuration in the file
|
||||||
|
`data/ice-servers.json`. In the case of a single STUN server, it should
|
||||||
|
look like this:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"urls": [
|
||||||
|
"stun:stun.example.org"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
In the case of s single TURN server, the `ice-servers.json` file should
|
||||||
|
look like this:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"urls": [
|
||||||
|
"turn:turn.example.org:443",
|
||||||
|
"turn:turn.example.org:443?transport=tcp"
|
||||||
|
],
|
||||||
|
"username": "galene",
|
||||||
|
"credential": "secret"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
It is more secure to use coturn's `use-auth-secret` option. If you do
|
||||||
|
that, then the `ice-servers.json` file should look like this:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"urls": [
|
||||||
|
"turn:turn.example.com:443",
|
||||||
|
"turn:turn.example.com:443?transport=tcp"
|
||||||
|
],
|
||||||
|
"username": "galene",
|
||||||
|
"credential": "secret",
|
||||||
|
"credentialType": "hmac-sha1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
For redundancy, you may set up multiple TURN servers, and ICE will use the
|
||||||
|
first one that works. If an `ice-servers.json` file is present and
|
||||||
|
Galène's built-in TURN server is enabled, then the external server will be
|
||||||
|
used in preference to the built-in server.
|
||||||
@@ -0,0 +1,575 @@
|
|||||||
|
# Galene manual
|
||||||
|
|
||||||
|
Please see the file [galene-install.md][1] for installation instructions.
|
||||||
|
Please see the section "Server administration" below for detailed
|
||||||
|
administration instructions.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Galene includes a web server that, by default, listens on port 8443.
|
||||||
|
Galene is therefore accessed on URLs such as:
|
||||||
|
|
||||||
|
https://galene.example.org:8443/
|
||||||
|
|
||||||
|
### The landing page
|
||||||
|
|
||||||
|
There is a landing page at the root of the server. The landing page
|
||||||
|
contains a list of all groups marked "public" in their configuration, as
|
||||||
|
well as a form that allows joining an arbitrary group.
|
||||||
|
|
||||||
|
Going through the landing page is not required: you are welcome to point
|
||||||
|
your browser directly at the desired group URL.
|
||||||
|
|
||||||
|
### The group pages
|
||||||
|
|
||||||
|
A group named e.g. *city-watch* has an associated page
|
||||||
|
`/group/city-watch/`. After login, it presents an interface consisting
|
||||||
|
of three panes:
|
||||||
|
|
||||||
|
- the left side pane contains the list of users who have joined the
|
||||||
|
group; every username doubles as a menu of group and user actions;
|
||||||
|
- the middle pane contains the chat messages published to the group;
|
||||||
|
- the main pane, on the right, contains the videos being streamed by
|
||||||
|
users in the group.
|
||||||
|
|
||||||
|
On mobile, only the latter pane is shown by default. An icon at the top
|
||||||
|
left opens the user list, and an icon in the main pane switches to the
|
||||||
|
chat.
|
||||||
|
|
||||||
|
### Buttons
|
||||||
|
|
||||||
|
There are up to three buttons at the top. The most important is The
|
||||||
|
*Enable*/*Disable* button, which switches on or off both the camera and
|
||||||
|
the microphone.
|
||||||
|
|
||||||
|
The *Mute* button mutes or unmutes the microphone; the microphone can be
|
||||||
|
muted remotely by the group moderator, but it cannot be unmuted remotely.
|
||||||
|
|
||||||
|
The *Share screen* button streams the contents of the screen or an
|
||||||
|
individual window.
|
||||||
|
|
||||||
|
### Side menu
|
||||||
|
|
||||||
|
There is a menu on the right of the user interface. It allows switching
|
||||||
|
off the camera (for audio-only sessions), choosing the camera and
|
||||||
|
microphone and setting the video throughput. The *Blackboard mode*
|
||||||
|
checkbox increases resolution and sacrifices framerate in favour of image
|
||||||
|
quality. The *Play local file* dialog streams a video from a local file.
|
||||||
|
|
||||||
|
### User list
|
||||||
|
|
||||||
|
There is a user list on the left, starting with the current user and
|
||||||
|
continuing with all users that have joined the current group.
|
||||||
|
|
||||||
|
The user list doubles as a set of menu. Clicking on the current user (the
|
||||||
|
first entry in the user list) opens the *group menu*, a menu with actions
|
||||||
|
that apply to the group as a whole. Clicking on a different user opens
|
||||||
|
a *user menu*, a menu that applies to that specific user.
|
||||||
|
|
||||||
|
### Chat pane
|
||||||
|
|
||||||
|
The center pane is a traditional chat interface, with an input form at the
|
||||||
|
bottom and the chat history above it. Chat history is never saved to
|
||||||
|
disk, and is erased after four hours (or whatever is specified in the
|
||||||
|
`"max-history-age"` field of the group definition).
|
||||||
|
|
||||||
|
Double-clicking on a message opens a contextual menu.
|
||||||
|
|
||||||
|
The chat form doubles as a command-line interface, which is especially
|
||||||
|
important for visually-impaired users, and more generally is often faster
|
||||||
|
than navigating the user interface. Commands start with a slash character
|
||||||
|
"`/`". The most important command is `/msg`, which sends a private
|
||||||
|
message to a given user. Type `/help` to display the list of available
|
||||||
|
commands.
|
||||||
|
|
||||||
|
### Inviting users
|
||||||
|
|
||||||
|
In order to generate an invitation link, choose the entry "Invite user" in
|
||||||
|
the group menu. This generates a link of the form
|
||||||
|
|
||||||
|
https://galene.example.org:8443/group/city-watch/?token=XXX
|
||||||
|
|
||||||
|
where the *XXX* part, known as the *token*, is a shared secret. Such
|
||||||
|
a link allows password-less login to the group, and may therefore be
|
||||||
|
shared e.g. over e-mail or instant messaging.
|
||||||
|
|
||||||
|
The invitiation functionality is usually restricted to the moderator;
|
||||||
|
however, groups may be configured with the `"unrestricted-tokens"` option,
|
||||||
|
which allows all users to generate tokens.
|
||||||
|
|
||||||
|
Tokens can be created, modified, and expires using the `/invite`,
|
||||||
|
`/reinvite` and `/revoke` commands.
|
||||||
|
nnnn
|
||||||
|
### File transfer
|
||||||
|
|
||||||
|
Galene includes a peer-to, end-to-end encrypted file transfer protocol.
|
||||||
|
In order to transfer a file, click on the receiver's entry in the user
|
||||||
|
list and choose "Send file".
|
||||||
|
|
||||||
|
### Group moderation
|
||||||
|
|
||||||
|
If a user has the *op* permission (short for *Operator*), then they have
|
||||||
|
access to a number of moderation tools.
|
||||||
|
|
||||||
|
For a moderator, the contextual menu that opens when clicking on an entry
|
||||||
|
in the user list is expanded with commands for muting a user, sending them
|
||||||
|
a warning, retrieving their IP address, or kicking them out from a group.
|
||||||
|
|
||||||
|
The group menu (opened by clicking on one's own entry in the user's list)
|
||||||
|
is extended with options to lock or to unlock a group (a locked group is
|
||||||
|
one that non-operator users cannot join).
|
||||||
|
|
||||||
|
All of the moderation commands are also available as command-line commands
|
||||||
|
(see above), which is helpful when moderating large groups.
|
||||||
|
|
||||||
|
# Server administration
|
||||||
|
|
||||||
|
|
||||||
|
## The global configuration file
|
||||||
|
|
||||||
|
The server may be configured in the JSON file `data/config.json`. This
|
||||||
|
file may look as follows:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"users":{"vetinari": {"password":"lagniappe", "permissions": "admin"}},
|
||||||
|
"canonicalHost": "galene.example.org",
|
||||||
|
"writableGroups": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
or, better, with a hashed password:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"users": {
|
||||||
|
"vetinari": {
|
||||||
|
"password":{"type":"bcrypt","key":"$2a$10$bTWW..."},
|
||||||
|
"permissions": "admin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"canonicalHost": "galene.example.org",
|
||||||
|
"writableGroups": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The file is initially set up using `galenectl initial-setup`, but may be
|
||||||
|
manually edited at any time (there is no need to restart the server). The
|
||||||
|
fields are as follows:
|
||||||
|
|
||||||
|
- `users` defines the users allowed to administer the server, and has the
|
||||||
|
same syntax as user definitions in groups (see below), except that the
|
||||||
|
only meaningful permission is `"admin"`;
|
||||||
|
|
||||||
|
- `writableGroups`: if true, then the API used by `galenectl` can be used
|
||||||
|
to modify group definitions; if unset or false, then only read-only
|
||||||
|
access is allowed;
|
||||||
|
|
||||||
|
- `allowOrigin` is an array that contains the list of HTTP origins that
|
||||||
|
are allowed to access the server;
|
||||||
|
|
||||||
|
- `allowAdminOrigin` is like `allowOrigin`, but applies to the
|
||||||
|
administrative API (the one used by `galenectl`);
|
||||||
|
|
||||||
|
- `proxyURL`: if running behind a reverse proxy, this specifies the root
|
||||||
|
URL that will be visible outside the proxy;
|
||||||
|
|
||||||
|
- `canonicalHost`: the canonical name of the host running the server;
|
||||||
|
clients that attempt to access the server using a different host name
|
||||||
|
will be redirected to the canonical one.
|
||||||
|
|
||||||
|
|
||||||
|
## Group definitions
|
||||||
|
|
||||||
|
Groups are described by JSON files in the `./groups/` directory. These
|
||||||
|
files are normally administered using the `galenectl` utility, but may
|
||||||
|
also be edited manually (there is no need to restart the server).
|
||||||
|
|
||||||
|
### Managing groups using `galenectl`
|
||||||
|
|
||||||
|
#### Creating, modifying, and suppressing groups
|
||||||
|
|
||||||
|
A group is created using `galenectl create-group`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl create-group -group city-watch
|
||||||
|
```
|
||||||
|
|
||||||
|
There are a number of options to customise the behaviour of the group, see
|
||||||
|
`galenectl create-group -help` for a full list. For example, in order to
|
||||||
|
create a group that allows unrestricted creation of tokens, say:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl create-group -group city-watch -unrestricted-tokens
|
||||||
|
```
|
||||||
|
|
||||||
|
For more advanced configuration, `galenectl create-group` can be invoked
|
||||||
|
with the `-json` flag, in which case it takes a JSON template on standard
|
||||||
|
input. The syntax of a JSON template is just like that of a group
|
||||||
|
definition file (see below), except that it must not contain the fields
|
||||||
|
`users` and `wildcard-user`. For example, in order to create a redirect
|
||||||
|
(see the section "Group description reference" below):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
echo '{"redirect": "https://galene.example.org:8443/group/city-watch/"}' | galenectl create-group -group amcw -json
|
||||||
|
```
|
||||||
|
|
||||||
|
Groups are modified using `galenectl update-group`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl update-group -group city-watch -unrestricted-tokens=false
|
||||||
|
```
|
||||||
|
|
||||||
|
If a JSON template is provided to `galenectl update-group`, then it is
|
||||||
|
merged with the existing group configuration. Entries may be suppressed
|
||||||
|
by setting them to `null` in the template:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
echo '{"redirect": null}' | galenectl update-group -group amcw
|
||||||
|
```
|
||||||
|
|
||||||
|
A group is deleted using `galenectl delete-group`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl delete-group -group amcw
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Creating, modifying, and suppressing users
|
||||||
|
|
||||||
|
A user entry is created with the `galenectl create-user` command :
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl create-user -group city-watch -user vimes -permissions op
|
||||||
|
```
|
||||||
|
|
||||||
|
If the `-permissions` flag is not specified, it defaults to `present`,
|
||||||
|
meaning that the user can participate in the chat and present videos to
|
||||||
|
the group. The other useful values are `message`, which allows a user
|
||||||
|
to participate in the chat only, and `observe`, which doesn't allow any
|
||||||
|
active participation.
|
||||||
|
|
||||||
|
A user is modified using `galenectl update-user`, and suppressed using
|
||||||
|
`galenectl delete-user`.
|
||||||
|
|
||||||
|
In order to be useful, a user entry needs to be assigned a password. This
|
||||||
|
is done with the `galenectl set-password` command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl set-password -group city-watch -user vimes
|
||||||
|
```
|
||||||
|
|
||||||
|
#### The fallback user
|
||||||
|
|
||||||
|
It is sometimes useful to allow multiple users to log-in using the same
|
||||||
|
password. This is achieved by defining the *wildcard* user:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl create-user -group city-watch -wildcard
|
||||||
|
galenectl set-password -group city-watch -wildcard
|
||||||
|
```
|
||||||
|
|
||||||
|
For open groups, where any user can login with any password, the wildcard
|
||||||
|
user's password is set to the password of type `wildcard`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl set-password -group city-watch -wildcard -type wildcard
|
||||||
|
```
|
||||||
|
|
||||||
|
See the section "Client authorisation" below for more information about
|
||||||
|
password types.
|
||||||
|
|
||||||
|
#### Automatic subgroups
|
||||||
|
|
||||||
|
It is sometimes necessary to create large numbers of identical groups.
|
||||||
|
For example, the author has been using Galene to supervise computer
|
||||||
|
science practicals, where up to 40 students are working in groups of two.
|
||||||
|
|
||||||
|
While it is possible to automate the creation of groups, by accessing
|
||||||
|
Galene's API, by scripting calls to galenectl, or by directly generating
|
||||||
|
files under `groups/`, Galene provides a facility known as *automatic
|
||||||
|
subgroups* that can be used to generate groups on demand.
|
||||||
|
|
||||||
|
Automatic subgroups are enabled by setting the `"auto-subgroups"`
|
||||||
|
field in the group description:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl create-group unseen-university -auto-subgroups
|
||||||
|
```
|
||||||
|
|
||||||
|
Whenever a user attempts to access a subgroup of `unseen-university`, for
|
||||||
|
example `unseen-university/hex`, the group is created in memory and
|
||||||
|
persists until it is empty and its chat history has expired. The main
|
||||||
|
group's operator can view the list of populated subgroups with the command
|
||||||
|
`/subgroups`.
|
||||||
|
|
||||||
|
#### Managing tokens
|
||||||
|
|
||||||
|
Tokens are normally managed using the `/invite`, `/reinvite` and `/expire`
|
||||||
|
commands in Galene's user interface, but they may also be managed using
|
||||||
|
the `galenectl` utility's `create-token`, `revoke-token`, `delete-token`
|
||||||
|
and `list-tokens` commands:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl create-token -group city-watch
|
||||||
|
galenectl list-tokens -l -group city-watch
|
||||||
|
```
|
||||||
|
|
||||||
|
A token that is generated with the `-include-subgroups` flag applies to
|
||||||
|
the whole hierarchy rooted at the given group, including both ordinary
|
||||||
|
groups and automatically generated subgroups.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl create-token -group city-watch -include-subgroups
|
||||||
|
```
|
||||||
|
|
||||||
|
Such a token can be attached to the root of the group hierarchy, and
|
||||||
|
therefore be valid for any group on the server:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
galenectl create-token -group '' -include-subgroups
|
||||||
|
```
|
||||||
|
|
||||||
|
### Group description reference
|
||||||
|
|
||||||
|
The definition for the group called *groupname* is in the file
|
||||||
|
`groups/groupname.json`; it does not contain the group name, which makes
|
||||||
|
it easy to copy or link group definitions. You may use subdirectories:
|
||||||
|
a file `groups/teaching/networking.json` defines a group called
|
||||||
|
*teaching/networking*.
|
||||||
|
|
||||||
|
Every group definition file contains a single JSON dictionary. All fields
|
||||||
|
are optional. The following fields are allowed:
|
||||||
|
|
||||||
|
- `users`: is a dictionary that maps user names to user descriptions (see
|
||||||
|
below);
|
||||||
|
|
||||||
|
- `wildcard-user` is a user description that will be used for usernames
|
||||||
|
with no matching entry in the `users` dictionary;
|
||||||
|
|
||||||
|
- `authKeys`, `authServer` and `authPortal`: see *Authorisation* below;
|
||||||
|
|
||||||
|
- `public`: if true, then the group is listed on the landing page;
|
||||||
|
|
||||||
|
- `displayName`: a human-friendly version of the group name; this is
|
||||||
|
displayed at the top of the group page;
|
||||||
|
|
||||||
|
- `description`: a human-readable description of the group; this is
|
||||||
|
displayed on the landing page for public groups;
|
||||||
|
|
||||||
|
- `contact`: a human-readable contact for this group, such as an e-mail
|
||||||
|
address, ignored by the server;
|
||||||
|
|
||||||
|
- `comment`: a human-readable string, ignored by the server;
|
||||||
|
|
||||||
|
- `max-clients`: the maximum number of clients that may join the group at
|
||||||
|
a time;
|
||||||
|
|
||||||
|
- `max-history-age`: the time, in seconds, during which chat history is
|
||||||
|
kept (default 14400, i.e. 4 hours);
|
||||||
|
|
||||||
|
- `not-before` and `expires`: the times (in ISO 8601 or RFC 3339 format)
|
||||||
|
between which joining the group is allowed;
|
||||||
|
|
||||||
|
- `allow-recording`: if true, then recording is allowed in this group;
|
||||||
|
|
||||||
|
- `unrestricted-tokens`: if true, then ordinary users (without the "op"
|
||||||
|
privilege) are allowed to create tokens;
|
||||||
|
|
||||||
|
- `allow-anonymous`: if true, then users may connect with an empty username;
|
||||||
|
|
||||||
|
- `auto-subgroups`: if true, then subgroups of the form `group/subgroup`
|
||||||
|
are automatically created when first accessed;
|
||||||
|
|
||||||
|
- `autolock`: if true, the group will start locked and become locked
|
||||||
|
whenever there are no clients with operator privileges;
|
||||||
|
|
||||||
|
- `autokick`: if true, all clients will be kicked out whenever there are
|
||||||
|
no clients with operator privileges; this is not recommended, prefer
|
||||||
|
the `autolock` option instead;
|
||||||
|
|
||||||
|
- `redirect`: if set, then attempts to join the group will be redirected
|
||||||
|
to the given URL; most other fields are ignored in this case;
|
||||||
|
|
||||||
|
- `codecs`: this is a list of codecs allowed in this group, see below for
|
||||||
|
possible values. The default is `["vp8", "opus"]`.
|
||||||
|
|
||||||
|
A user definition is a dictionary with entries `password` and
|
||||||
|
`permission`. The value of the `password` field is either a plaintext
|
||||||
|
password, or a hashed password generated for example by the `galenectl
|
||||||
|
hash-password` command. The value of the `permissions` field can either
|
||||||
|
be an array of individual permissions (not recommended), or one of the
|
||||||
|
following strings:
|
||||||
|
|
||||||
|
- `op`, a group operator, with all rights except administering the group;
|
||||||
|
- `present`, an ordinary user with the right to publish audio and video
|
||||||
|
streams and send chat messages;
|
||||||
|
- `message`, a user with the right to send chat messages;
|
||||||
|
- `observe`, a user that receives media streams and chat messages, but
|
||||||
|
is not allowed to send them;
|
||||||
|
- `caption`, a user with the right to display captions (only);
|
||||||
|
- `admin`, a user with the right to administer the group (only).
|
||||||
|
|
||||||
|
The value of the `codecs` field is an array of codecs allowed in the
|
||||||
|
group. Supported video codecs include:
|
||||||
|
|
||||||
|
- `"vp8"` (compatible with all supported browsers, full functionality);
|
||||||
|
- `"vp9"` (better video quality, but incompatible with Safari; somewhat
|
||||||
|
buggy in Firefox; full functionality);
|
||||||
|
- `"av1"` (even better video quality, only supported by some browsers,
|
||||||
|
limited functionality: no recording, no SVC);
|
||||||
|
- `"h264"` (well supported by Apple devices, but incompatible with Debian
|
||||||
|
Linux and with some older Android devices, SVC is not supported; might
|
||||||
|
be covered by patents in some countries).
|
||||||
|
|
||||||
|
Supported audio codecs include `"opus"`, `"g722"`, `"pcmu"` and `"pcma"`.
|
||||||
|
Only Opus can be recorded to disk. There is no good reason to use
|
||||||
|
anything except Opus.
|
||||||
|
|
||||||
|
## Client Authorisation
|
||||||
|
|
||||||
|
Galene implements three authorisation methods: a username/password
|
||||||
|
authorisation scheme, a scheme using stateful tokens, and a mechanism
|
||||||
|
based on cryptographic tokens. The former two mechanism are intended to
|
||||||
|
be used in standalone installations, while the cryptographic mechanism is
|
||||||
|
designed to allow easy integration with an existing authorisation
|
||||||
|
infrastructure (such as LDAP, OAuth2, or even Unix passwords).
|
||||||
|
|
||||||
|
### Password authorisation
|
||||||
|
|
||||||
|
When password authorisation is used, authorised usernames and password are
|
||||||
|
defined directly in the group configuration file, in the `users` and
|
||||||
|
`wildcard-user` entries. The `users` entry is a dictionary that maps user
|
||||||
|
names to user descriptions; the `wildcard-user` is a user description
|
||||||
|
that is used with usernames that don't appear in `users`. These two
|
||||||
|
entries are usually managed by the `galenectl` utility.
|
||||||
|
|
||||||
|
Every user description is a dictionary with fields `password` and
|
||||||
|
`permissions`. The `password` field may be a literal password string, or
|
||||||
|
a dictionary describing a hashed password or a wildcard. The
|
||||||
|
`permissions` field should be one of `op`, `present`, `message` or
|
||||||
|
`observe`. (An array of Galene's internal permissions is also allowed,
|
||||||
|
but this is not recommended, since internal permissions may vary from
|
||||||
|
version to version).
|
||||||
|
|
||||||
|
For example, the entry
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"users": {"vimes": {"password": "sybil", "permissions": "op"}}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
specifies that user "vimes" may login as operator with password "sybil", while
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"wildcard-user": {"password": "1234", "permissions": "present"}
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
allows any username with password *1234*. Finally,
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"wildcard-user":
|
||||||
|
{"password": {"type": "wildcard"}, "permissions": "present"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
allows any username with any password.
|
||||||
|
|
||||||
|
### Hashed passwords
|
||||||
|
|
||||||
|
For security reasons, passwords are usually hashed before being stored in
|
||||||
|
group descriptions (in fact, the `galenectl` utility does not even support
|
||||||
|
storing plaintext passwords). A hased password is represented as a JSON
|
||||||
|
dicttionary with a field `type` and a number of type-specific fields.
|
||||||
|
|
||||||
|
A user entry with a hashed password looks like this:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"users": {
|
||||||
|
"vimes": {
|
||||||
|
"password": {
|
||||||
|
"type": "pbkdf2",
|
||||||
|
"hash": "sha-256",
|
||||||
|
"key": "f591c35604e6aef572851d9c3543c812566b032b6dc083c81edd15cc24449913",
|
||||||
|
"salt": "92bff2ace56fe38f",
|
||||||
|
"iterations": 4096
|
||||||
|
},
|
||||||
|
"permissions": "op"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Hashed passwords are normally generated transparently to the user by the
|
||||||
|
`galenectl set-password` command. When edition group description files
|
||||||
|
manually, hashed passwords can be generated with the `galenectl hash-password`
|
||||||
|
utility.
|
||||||
|
|
||||||
|
### Stateful tokens
|
||||||
|
|
||||||
|
Stateful tokens are created by the `/invite` command in the Galene user
|
||||||
|
interface or by the `galenectl create-token` command; see the section
|
||||||
|
*Managing tokens* above. They are stored in the file
|
||||||
|
`data/var/tokens.jsonl`, which, on most filesystems, can be safely backed
|
||||||
|
up without stopping the server.
|
||||||
|
|
||||||
|
### Cryptographic tokens
|
||||||
|
|
||||||
|
In many cases, it is useful to delegate authorisation decisions to a third
|
||||||
|
party, such as an LDAP or OAuth2 client. Galene implements delegation of
|
||||||
|
authorisation decisions using cryptographic tokens generated by a third
|
||||||
|
party known as an *authorisaton server*. Two authorisation servers are
|
||||||
|
available: an [LDAP client][2], and a [sample server written in Python][3].
|
||||||
|
|
||||||
|
When an authorisation server is used, the `"authKeys"` entry of the group
|
||||||
|
configuration file specifies one or more public keys in JWK format (with
|
||||||
|
the restriction that the "alg" key must be specified explicitly):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"authKeys": [{
|
||||||
|
"kty": "oct",
|
||||||
|
"alg": "HS256",
|
||||||
|
"k": "MYz3IfCq4Yq-UmPdNqWEOdPl4C_m9imHHs9uveDUJGQ",
|
||||||
|
}, {
|
||||||
|
"kty": "EC",
|
||||||
|
"alg": "ES256",
|
||||||
|
"crv": "P-256",
|
||||||
|
"x": "dElK9qBNyCpRXdvJsn4GdjrFzScSzpkz_I0JhKbYC88",
|
||||||
|
"y": "pBhVb37haKvwEoleoW3qxnT4y5bK35_RTP7_RmFKR6Q",
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If multiple keys are provided, then they will all be tried in turn, unless
|
||||||
|
the token includes the "kid" header field, in which case only the
|
||||||
|
specified key will be used.
|
||||||
|
|
||||||
|
The group file should also specify either an authorisation server or an
|
||||||
|
authorisation portal. An authorisation server is specified using the
|
||||||
|
`"authServer"` key:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"authServer": "https://auth.example.org",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If an authorisation server is specified, then the client, after it prompts
|
||||||
|
for a password, will request a token from the authorisation server and
|
||||||
|
join the group using token authentication. The password is never
|
||||||
|
communicated to the server.
|
||||||
|
|
||||||
|
Alternatively, the group file may specify an authorisation portal using
|
||||||
|
the `"authPortal"` key
|
||||||
|
|
||||||
|
If an authorisation portal is specified, then the default client will
|
||||||
|
redirect initial client connections to the authorisation portal. The
|
||||||
|
authorisation portal is expected to authorise the client and then redirect
|
||||||
|
it to Galene with the `username` and `token` query parameters set.
|
||||||
|
|
||||||
|
[1]: <galene-install.md>
|
||||||
|
[2]: <https://github.com/jech/galene-imap/>
|
||||||
|
[3]: <https://github.com/jech/galene-sample-auth-server/>
|
||||||
Reference in New Issue
Block a user