Rebrand project as Skald
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
*~
|
*~
|
||||||
/galene
|
/skald
|
||||||
/galenectl/galenectl
|
/skaldctl/skaldctl
|
||||||
/data
|
/data
|
||||||
/groups/**/*.json
|
/groups/**/*.json
|
||||||
/static/**/*.d.ts
|
/static/**/*.d.ts
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
Skald 0.1 (unreleased):
|
||||||
|
|
||||||
|
* Forked from Galene after commit f718385.
|
||||||
|
* Renamed the project, module, command, control tool, static assets, and
|
||||||
|
documentation entrypoints from Galene to Skald.
|
||||||
|
|
||||||
Galene 1.1 (unreleased):
|
Galene 1.1 (unreleased):
|
||||||
|
|
||||||
* Implemented "galenectl initial-setup".
|
* Implemented "galenectl initial-setup".
|
||||||
|
|||||||
@@ -1,59 +1,47 @@
|
|||||||
# The Galene videoconferencing system
|
# Skald
|
||||||
|
|
||||||
Galene is a fully-features videoconferencing system that is easy to deploy
|
Skald is a hard fork of Galene that is being turned into an audio-only
|
||||||
and requires very moderate server resources. It is described at
|
hall conferencing server. The current development repository is
|
||||||
<https://galene.org>.
|
<https://git.stormux.org/storm/skald>.
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/jech/galene
|
git clone https://git.stormux.org/storm/skald
|
||||||
cd galene
|
cd skald
|
||||||
CGO_ENABLED=0 go build -ldflags='-s -w'
|
CGO_ENABLED=0 go build -ldflags='-s -w'
|
||||||
mkdir groups
|
mkdir groups
|
||||||
echo '{"users": {"vimes": {"password":"sybil", "permissions":"op"}}}' > groups/night-watch.json
|
echo '{"users": {"vimes": {"password":"sybil", "permissions":"op"}}}' > groups/night-watch.json
|
||||||
./galene &
|
./skald &
|
||||||
```
|
```
|
||||||
|
|
||||||
Point your browser at <https://localhost:8443/group/night-watch/>, ignore
|
Point your browser at <https://localhost:8443/group/night-watch/>, ignore
|
||||||
the unknown certificate warning, and log in with username *vimes* and
|
the unknown certificate warning, and log in with username *vimes* and
|
||||||
password *sybil*.
|
password *sybil*.
|
||||||
|
|
||||||
For full installation instructions, please see the file [galene-install.md][1]
|
For full installation instructions, please see the file [skald-install.md][1]
|
||||||
in this directory.
|
in this directory.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
* [galene-install.md][1]: full installation instructions
|
* [skald-install.md][1]: full installation instructions
|
||||||
* [galene.md][2]: usage and administration;
|
* [skald.md][2]: usage and administration;
|
||||||
* [galene-client.md][3]: writing clients;
|
* [skald-client.md][3]: writing clients;
|
||||||
* [galene-protocol.md][4]: the client protocol;
|
* [skald-protocol.md][4]: the client protocol;
|
||||||
* [galene-api.md][5]: Galene's administrative API.
|
* [skald-api.md][5]: Skald's administrative API.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
In order to contribute to Galene, you may:
|
Skald is currently being developed at
|
||||||
|
<https://git.stormux.org/storm/skald>.
|
||||||
* send patches to [the Galene mailing list][6] by sending mail to
|
|
||||||
<galene@lists.galene.org>;
|
|
||||||
* submit pull requests on GitHub.
|
|
||||||
|
|
||||||
For general discussion, please use the [Galene mailing list][6] (feel free
|
|
||||||
to send mail without subscribing). Please do not use Github for general
|
|
||||||
discussion.
|
|
||||||
|
|
||||||
## Further information
|
## Further information
|
||||||
|
|
||||||
Galène's web page is at <https://galene.org>.
|
Skald is derived from Galene by Juliusz Chroboczek. Galene's web page is at
|
||||||
|
<https://galene.org>.
|
||||||
|
|
||||||
Answers to common questions and issues are at <https://galene.org/faq.html>.
|
[1]: <skald-install.md>
|
||||||
|
[2]: <skald.md>
|
||||||
|
[3]: <skald-client.md>
|
||||||
-- Juliusz Chroboczek <https://www.irif.fr/~jch/>
|
[4]: <skald-protocol.md>
|
||||||
|
[5]: <skald-api.md>
|
||||||
[1]: <galene-install.md>
|
|
||||||
[2]: <galene.md>
|
|
||||||
[3]: <galene-client.md>
|
|
||||||
[4]: <galene-protocol.md>
|
|
||||||
[5]: <galene-api.md>
|
|
||||||
[6]: <https://lists.galene.org/>
|
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ import (
|
|||||||
|
|
||||||
"github.com/jech/samplebuilder"
|
"github.com/jech/samplebuilder"
|
||||||
|
|
||||||
gcodecs "github.com/jech/galene/codecs"
|
gcodecs "git.stormux.org/storm/skald/codecs"
|
||||||
"github.com/jech/galene/conn"
|
"git.stormux.org/storm/skald/conn"
|
||||||
"github.com/jech/galene/group"
|
"git.stormux.org/storm/skald/group"
|
||||||
"github.com/jech/galene/rtptime"
|
"git.stormux.org/storm/skald/rtptime"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jech/galene/rtptime"
|
"git.stormux.org/storm/skald/rtptime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSanitise(t *testing.T) {
|
func TestSanitise(t *testing.T) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jech/galene/rtptime"
|
"git.stormux.org/storm/skald/rtptime"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Estimator struct {
|
type Estimator struct {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jech/galene/rtptime"
|
"git.stormux.org/storm/skald/rtptime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEstimator(t *testing.T) {
|
func TestEstimator(t *testing.T) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module github.com/jech/galene
|
module git.stormux.org/storm/skald
|
||||||
|
|
||||||
go 1.21
|
go 1.21
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ import (
|
|||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
|
|
||||||
"github.com/jech/galene/conn"
|
"git.stormux.org/storm/skald/conn"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RawPassword struct {
|
type RawPassword struct {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jech/galene/token"
|
"git.stormux.org/storm/skald/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrTagMismatch = errors.New("tag mismatch")
|
var ErrTagMismatch = errors.New("tag mismatch")
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ import (
|
|||||||
"github.com/pion/interceptor"
|
"github.com/pion/interceptor"
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
|
|
||||||
"github.com/jech/galene/token"
|
"git.stormux.org/storm/skald/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Directory, DataDirectory string
|
var Directory, DataDirectory string
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
|
|
||||||
"github.com/jech/galene/turnserver"
|
"git.stormux.org/storm/skald/turnserver"
|
||||||
)
|
)
|
||||||
|
|
||||||
type timeoutError struct{}
|
type timeoutError struct{}
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
|
|
||||||
"github.com/jech/galene/turnserver"
|
"git.stormux.org/storm/skald/turnserver"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPassword(t *testing.T) {
|
func TestPassword(t *testing.T) {
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ package jitter
|
|||||||
import (
|
import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/jech/galene/rtptime"
|
"git.stormux.org/storm/skald/rtptime"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Estimator struct {
|
type Estimator struct {
|
||||||
|
|||||||
+10
-10
@@ -14,16 +14,16 @@ import (
|
|||||||
"github.com/pion/sdp/v3"
|
"github.com/pion/sdp/v3"
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
|
|
||||||
"github.com/jech/galene/codecs"
|
"git.stormux.org/storm/skald/codecs"
|
||||||
"github.com/jech/galene/conn"
|
"git.stormux.org/storm/skald/conn"
|
||||||
"github.com/jech/galene/estimator"
|
"git.stormux.org/storm/skald/estimator"
|
||||||
"github.com/jech/galene/group"
|
"git.stormux.org/storm/skald/group"
|
||||||
"github.com/jech/galene/ice"
|
"git.stormux.org/storm/skald/ice"
|
||||||
"github.com/jech/galene/jitter"
|
"git.stormux.org/storm/skald/jitter"
|
||||||
"github.com/jech/galene/packetcache"
|
"git.stormux.org/storm/skald/packetcache"
|
||||||
"github.com/jech/galene/packetmap"
|
"git.stormux.org/storm/skald/packetmap"
|
||||||
"github.com/jech/galene/rtptime"
|
"git.stormux.org/storm/skald/rtptime"
|
||||||
"github.com/jech/galene/unbounded"
|
"git.stormux.org/storm/skald/unbounded"
|
||||||
)
|
)
|
||||||
|
|
||||||
type bitrate struct {
|
type bitrate struct {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package rtpconn
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jech/galene/rtptime"
|
"git.stormux.org/storm/skald/rtptime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDownTrackAtomics(t *testing.T) {
|
func TestDownTrackAtomics(t *testing.T) {
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import (
|
|||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
|
|
||||||
"github.com/jech/galene/codecs"
|
"git.stormux.org/storm/skald/codecs"
|
||||||
"github.com/jech/galene/packetcache"
|
"git.stormux.org/storm/skald/packetcache"
|
||||||
"github.com/jech/galene/rtptime"
|
"git.stormux.org/storm/skald/rtptime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func readLoop(track *rtpUpTrack) {
|
func readLoop(track *rtpUpTrack) {
|
||||||
|
|||||||
+2
-2
@@ -4,8 +4,8 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jech/galene/rtptime"
|
"git.stormux.org/storm/skald/rtptime"
|
||||||
"github.com/jech/galene/stats"
|
"git.stormux.org/storm/skald/stats"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *webClient) GetStats() *stats.Client {
|
func (c *webClient) GetStats() *stats.Client {
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jech/galene/conn"
|
"git.stormux.org/storm/skald/conn"
|
||||||
"github.com/jech/galene/packetcache"
|
"git.stormux.org/storm/skald/packetcache"
|
||||||
"github.com/jech/galene/rtptime"
|
"git.stormux.org/storm/skald/rtptime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// packetIndex is a request to send a packet from the cache.
|
// packetIndex is a request to send a packet from the cache.
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ import (
|
|||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
|
|
||||||
"github.com/jech/galene/conn"
|
"git.stormux.org/storm/skald/conn"
|
||||||
"github.com/jech/galene/diskwriter"
|
"git.stormux.org/storm/skald/diskwriter"
|
||||||
"github.com/jech/galene/estimator"
|
"git.stormux.org/storm/skald/estimator"
|
||||||
"github.com/jech/galene/group"
|
"git.stormux.org/storm/skald/group"
|
||||||
"github.com/jech/galene/ice"
|
"git.stormux.org/storm/skald/ice"
|
||||||
"github.com/jech/galene/token"
|
"git.stormux.org/storm/skald/token"
|
||||||
"github.com/jech/galene/unbounded"
|
"git.stormux.org/storm/skald/unbounded"
|
||||||
)
|
)
|
||||||
|
|
||||||
func errorToWSCloseMessage(id string, err error) (*clientMessage, []byte) {
|
func errorToWSCloseMessage(id string, err error) (*clientMessage, []byte) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jech/galene/token"
|
"git.stormux.org/storm/skald/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
var tokens = []string{
|
var tokens = []string{
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/jech/galene/conn"
|
"git.stormux.org/storm/skald/conn"
|
||||||
"github.com/jech/galene/group"
|
"git.stormux.org/storm/skald/group"
|
||||||
"github.com/jech/galene/sdpfrag"
|
"git.stormux.org/storm/skald/sdpfrag"
|
||||||
|
|
||||||
"github.com/pion/sdp/v3"
|
"github.com/pion/sdp/v3"
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
# Galene's administrative API
|
# Skald's administrative API
|
||||||
|
|
||||||
Galene provides an HTTP-based API that can be used to create groups and
|
Skald provides an HTTP-based API that can be used to create groups and
|
||||||
users. For example, in order to create a group, a client may do
|
users. For example, in order to create a group, a client may do
|
||||||
|
|
||||||
PUT /galene-api/v0/.groups/groupname/
|
PUT /skald-api/v0/.groups/groupname/
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
If-None-Match: *
|
If-None-Match: *
|
||||||
|
|
||||||
@@ -11,12 +11,12 @@ The `If-None-Match` header avoids overwriting an existing group.
|
|||||||
|
|
||||||
In order to edit a group definition, a client first does
|
In order to edit a group definition, a client first does
|
||||||
|
|
||||||
GET /galene-api/v0/.groups/groupname/
|
GET /skald-api/v0/.groups/groupname/
|
||||||
|
|
||||||
This yields the group definition and an entity tag (in the ETag header).
|
This yields the group definition and an entity tag (in the ETag header).
|
||||||
The client then modifies the group defintion, and does
|
The client then modifies the group defintion, and does
|
||||||
|
|
||||||
PUT /galene-api/v0/.groups/groupname/
|
PUT /skald-api/v0/.groups/groupname/
|
||||||
If-Match: "abcd"
|
If-Match: "abcd"
|
||||||
|
|
||||||
where "abcd" is the entity tag returned by the GET request. If the group
|
where "abcd" is the entity tag returned by the GET request. If the group
|
||||||
@@ -27,13 +27,13 @@ in the case of a concurrent modification.
|
|||||||
|
|
||||||
## Endpoints
|
## Endpoints
|
||||||
|
|
||||||
The API is located under `/galene-api/v0/`. The `/v0/` is a version number,
|
The API is located under `/skald-api/v0/`. The `/v0/` is a version number,
|
||||||
and will be incremented if we ever find out that the current API cannot be
|
and will be incremented if we ever find out that the current API cannot be
|
||||||
extended in a backwards compatible manner.
|
extended in a backwards compatible manner.
|
||||||
|
|
||||||
### Statistics
|
### Statistics
|
||||||
|
|
||||||
/galene-api/v0/.stats
|
/skald-api/v0/.stats
|
||||||
|
|
||||||
Provides a number of statistics about the running server, in JSON. The
|
Provides a number of statistics about the running server, in JSON. The
|
||||||
exact format is undocumented, and may change between versions. The only
|
exact format is undocumented, and may change between versions. The only
|
||||||
@@ -41,14 +41,14 @@ allowed methods are HEAD and GET.
|
|||||||
|
|
||||||
### List of groups
|
### List of groups
|
||||||
|
|
||||||
/galene-api/v0/.groups/
|
/skald-api/v0/.groups/
|
||||||
|
|
||||||
Returns a list of groups, as a JSON array. The only allowed methods are
|
Returns a list of groups, as a JSON array. The only allowed methods are
|
||||||
HEAD and GET.
|
HEAD and GET.
|
||||||
|
|
||||||
### Group definition
|
### Group definition
|
||||||
|
|
||||||
/galene-api/v0/.groups/groupname
|
/skald-api/v0/.groups/groupname
|
||||||
|
|
||||||
Contains a "sanitised" group definition in JSON format, analogous to the
|
Contains a "sanitised" group definition in JSON format, analogous to the
|
||||||
on-disk format but without any user definitions or cryptographic keys.
|
on-disk format but without any user definitions or cryptographic keys.
|
||||||
@@ -57,7 +57,7 @@ content-type is `application/json`.
|
|||||||
|
|
||||||
### Authentication keys
|
### Authentication keys
|
||||||
|
|
||||||
/galene-api/v0/.groups/groupname/.keys
|
/skald-api/v0/.groups/groupname/.keys
|
||||||
|
|
||||||
Contains the keys used for validation of stateless tokens, encoded as
|
Contains the keys used for validation of stateless tokens, encoded as
|
||||||
a JSON key set (RFC 7517). Allowed methods are PUT and DELETE. The only
|
a JSON key set (RFC 7517). Allowed methods are PUT and DELETE. The only
|
||||||
@@ -65,16 +65,16 @@ accepted content-type is `application/jwk-set+json`.
|
|||||||
|
|
||||||
### List of users
|
### List of users
|
||||||
|
|
||||||
/galene-api/v0/.groups/groupname/.users/
|
/skald-api/v0/.groups/groupname/.users/
|
||||||
|
|
||||||
Returns a list of users, as a JSON array. The only allowed methods are
|
Returns a list of users, as a JSON array. The only allowed methods are
|
||||||
HEAD and GET.
|
HEAD and GET.
|
||||||
|
|
||||||
### User definitions
|
### User definitions
|
||||||
|
|
||||||
/galene-api/v0/.groups/groupname/.users/username
|
/skald-api/v0/.groups/groupname/.users/username
|
||||||
/galene-api/v0/.groups/groupname/.empty-user
|
/skald-api/v0/.groups/groupname/.empty-user
|
||||||
/galene-api/v0/.groups/groupname/.wildcard-user
|
/skald-api/v0/.groups/groupname/.wildcard-user
|
||||||
|
|
||||||
Contains a "sanitised" user definition (without any passwords), a JSON
|
Contains a "sanitised" user definition (without any passwords), a JSON
|
||||||
object with a single field `permissions`. The entries `.empty-user` and
|
object with a single field `permissions`. The entries `.empty-user` and
|
||||||
@@ -84,9 +84,9 @@ only accepted content-type is `application/json`.
|
|||||||
|
|
||||||
### Passwords
|
### Passwords
|
||||||
|
|
||||||
/galene-api/v0/.groups/groupname/.users/username/.password
|
/skald-api/v0/.groups/groupname/.users/username/.password
|
||||||
/galene-api/v0/.groups/groupname/.empty-user/.password
|
/skald-api/v0/.groups/groupname/.empty-user/.password
|
||||||
/galene-api/v0/.groups/groupname/.wildcard-user/.password
|
/skald-api/v0/.groups/groupname/.wildcard-user/.password
|
||||||
|
|
||||||
Contains the password of a given user. The PUT method takes a full
|
Contains the password of a given user. The PUT method takes a full
|
||||||
password definition, identical to what can appear in the `"password"`
|
password definition, identical to what can appear in the `"password"`
|
||||||
@@ -97,7 +97,7 @@ POST.
|
|||||||
|
|
||||||
### Wildcard user
|
### Wildcard user
|
||||||
|
|
||||||
/galene-api/v0/.groups/groupname/.wildcard-user
|
/skald-api/v0/.groups/groupname/.wildcard-user
|
||||||
|
|
||||||
Contains a dictionary defining the wildcard user, in the same format as
|
Contains a dictionary defining the wildcard user, in the same format as
|
||||||
the dictionary defining an ordinary user. Allowed methods are HEAD, GET,
|
the dictionary defining an ordinary user. Allowed methods are HEAD, GET,
|
||||||
@@ -105,14 +105,14 @@ PUT and DELETE.
|
|||||||
|
|
||||||
### Wildcard user password
|
### Wildcard user password
|
||||||
|
|
||||||
/galene-api/v0/.groups/groupname/.wildcard-user/.password
|
/skald-api/v0/.groups/groupname/.wildcard-user/.password
|
||||||
|
|
||||||
This is analogous to the password of an ordinary user. Allowed methods
|
This is analogous to the password of an ordinary user. Allowed methods
|
||||||
are PUT, POST and DELETE.
|
are PUT, POST and DELETE.
|
||||||
|
|
||||||
### List of stateful tokens
|
### List of stateful tokens
|
||||||
|
|
||||||
/galene-api/v0/.groups/groupname/.users/username/.tokens/
|
/skald-api/v0/.groups/groupname/.users/username/.tokens/
|
||||||
|
|
||||||
GET returns the list of stateful tokens, as a JSON array. POST creates
|
GET returns the list of stateful tokens, as a JSON array. POST creates
|
||||||
a new token, and returns its name in the `Location` header. Allowed
|
a new token, and returns its name in the `Location` header. Allowed
|
||||||
@@ -120,7 +120,7 @@ methods are HEAD, GET and POST.
|
|||||||
|
|
||||||
### Stateful token
|
### Stateful token
|
||||||
|
|
||||||
/galene-api/v0/.groups/groupname/.users/username/.tokens/token
|
/skald-api/v0/.groups/groupname/.users/username/.tokens/token
|
||||||
|
|
||||||
The full contents of a single token, in JSON. The exact format may change
|
The full contents of a single token, in JSON. The exact format may change
|
||||||
between versions, so a client should first GET a token, update one or more
|
between versions, so a client should first GET a token, update one or more
|
||||||
@@ -4,11 +4,11 @@ The frontend is written in JavaScript and is split into two files:
|
|||||||
|
|
||||||
- `protocol.js` contains the low-level functions that interact with the
|
- `protocol.js` contains the low-level functions that interact with the
|
||||||
server;
|
server;
|
||||||
- `galene.js` contains the user interface.
|
- `skald.js` contains the user interface.
|
||||||
|
|
||||||
A simpler example client can be found in the directory `static/example`.
|
A simpler example client can be found in the directory `static/example`.
|
||||||
|
|
||||||
A new frontend may either implement Galène's client-server protocol from
|
A new frontend may either implement Skald's client-server protocol from
|
||||||
scratch, or it may use the functionality of `protocol.js`. This document
|
scratch, or it may use the functionality of `protocol.js`. This document
|
||||||
documents the latter approach.
|
documents the latter approach.
|
||||||
|
|
||||||
@@ -197,7 +197,7 @@ audio energy (the square of the volume) for streams in the down direction.
|
|||||||
|
|
||||||
# Peer-to-peer file transfer
|
# Peer-to-peer file transfer
|
||||||
|
|
||||||
Galene's client allows users to transfer files during a meeting. The
|
Skald's client allows users to transfer files during a meeting. The
|
||||||
protocol is peer-to-peer: the clients exchange network parameters and
|
protocol is peer-to-peer: the clients exchange network parameters and
|
||||||
cryptographic keys through the server (over messages of type
|
cryptographic keys through the server (over messages of type
|
||||||
`usermessage`), but all file transfer is performed directly between the
|
`usermessage`), but all file transfer is performed directly between the
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
# Galene installation instructions
|
# Skald installation instructions
|
||||||
|
|
||||||
## Basic installation
|
## Basic installation
|
||||||
|
|
||||||
### Build the Galene binary
|
### Build the Skald binary
|
||||||
|
|
||||||
Say:
|
Say:
|
||||||
|
|
||||||
@@ -28,8 +28,8 @@ CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags='-s -w'
|
|||||||
|
|
||||||
### Optional: install libraries for background blur
|
### Optional: install libraries for background blur
|
||||||
|
|
||||||
Galene's client uses Google's MediaPipe library to implement background
|
Skald's client uses Google's MediaPipe library to implement background
|
||||||
blur. This library is optional, and if it is absent, Galene will
|
blur. This library is optional, and if it is absent, Skald will
|
||||||
disable the menu entries for background blur.
|
disable the menu entries for background blur.
|
||||||
|
|
||||||
Optionally install Google's MediaPipe library:
|
Optionally install Google's MediaPipe library:
|
||||||
@@ -53,8 +53,8 @@ If you don't have `wget` on your system, try using `curl -O` instead.
|
|||||||
### Deploy to your server
|
### Deploy to your server
|
||||||
|
|
||||||
The following instructions assume that your server is called
|
The following instructions assume that your server is called
|
||||||
`galene.example.org` and that you have already created a dedicated user
|
`skald.example.org` and that you have already created a dedicated user
|
||||||
called `galene`.
|
called `skald`.
|
||||||
|
|
||||||
First, make sure that the `groups` and `data` directories exist:
|
First, make sure that the `groups` and `data` directories exist:
|
||||||
|
|
||||||
@@ -62,37 +62,37 @@ First, make sure that the `groups` and `data` directories exist:
|
|||||||
mkdir groups data
|
mkdir groups data
|
||||||
```
|
```
|
||||||
|
|
||||||
Now copy the `galene` binary, and the directories `static`, `data` and
|
Now copy the `skald` binary, and the directories `static`, `data` and
|
||||||
`groups` to the server:
|
`groups` to the server:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
rsync -a galene static data groups galene@galene.example.org:
|
rsync -a skald static data groups skald@skald.example.org:
|
||||||
```
|
```
|
||||||
|
|
||||||
If you don't have a TLS certificate, Galene will generate a self-signed
|
If you don't have a TLS certificate, Skald will generate a self-signed
|
||||||
certificate (and print a warning to the logs). If you have a certificate,
|
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`:
|
install it in the files `data/cert.pem` and `data/key.pem`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
ssh galene@galene.example.org
|
ssh skald@skald.example.org
|
||||||
sudo cp /etc/letsencrypt/live/galene.example.org/fullchain.pem data/cert.pem
|
sudo cp /etc/letsencrypt/live/skald.example.org/fullchain.pem data/cert.pem
|
||||||
sudo cp /etc/letsencrypt/live/galene.example.org/privkey.pem data/key.pem
|
sudo cp /etc/letsencrypt/live/skald.example.org/privkey.pem data/key.pem
|
||||||
sudo chown galene:galene data/*.pem
|
sudo chown skald:skald data/*.pem
|
||||||
chmod go-rw data/key.pem
|
chmod go-rw data/key.pem
|
||||||
```
|
```
|
||||||
|
|
||||||
Since certificates are regularly rotated, this should be done in a monthly
|
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).
|
cron job (or a *SystemD* timer unit, if you're feeling particularly kinky).
|
||||||
|
|
||||||
### Run Galene on the server
|
### Run Skald on the server
|
||||||
|
|
||||||
Arrange to run the binary on the server. If you never reboot your server,
|
Arrange to run the binary on the server. If you never reboot your server,
|
||||||
just do:
|
just do:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
ssh galene@galene.example.org
|
ssh skald@skald.example.org
|
||||||
ulimit -n 65536
|
ulimit -n 65536
|
||||||
nohup ./galene &
|
nohup ./skald &
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are using *runit*, use a script like the following:
|
If you are using *runit*, use a script like the following:
|
||||||
@@ -100,58 +100,58 @@ If you are using *runit*, use a script like the following:
|
|||||||
```sh
|
```sh
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
exec 2>&1
|
exec 2>&1
|
||||||
cd ~galene
|
cd ~skald
|
||||||
ulimit -n 65536
|
ulimit -n 65536
|
||||||
exec setuidgid galene ./galene
|
exec setuidgid skald ./skald
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are using *SystemD*, put the following in
|
If you are using *SystemD*, put the following in
|
||||||
`/etc/systemd/system/galene.service` (and then run `systemctl daemon-reload`):
|
`/etc/systemd/system/skald.service` (and then run `systemctl daemon-reload`):
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Galene
|
Description=Skald
|
||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
WorkingDirectory=/home/galene
|
WorkingDirectory=/home/skald
|
||||||
User=galene
|
User=skald
|
||||||
Group=galene
|
Group=skald
|
||||||
ExecStart=/home/galene/galene
|
ExecStart=/home/skald/skald
|
||||||
LimitNOFILE=65536
|
LimitNOFILE=65536
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set up galenectl
|
### Set up skaldctl
|
||||||
|
|
||||||
There are two ways to administer a Galene instance: by manually editing
|
There are two ways to administer a Skald instance: by manually editing
|
||||||
JSON files on the server, or by using the `galenectl` utility.
|
JSON files on the server, or by using the `skaldctl` utility.
|
||||||
The `galenectl` utility is recommended, since it avoids issues with
|
The `skaldctl` utility is recommended, since it avoids issues with
|
||||||
concurrent modifications and is less error-prone than the alternative.
|
concurrent modifications and is less error-prone than the alternative.
|
||||||
|
|
||||||
Build the `galenectl` utility, and copy it somewhere on your path:
|
Build the `skaldctl` utility, and copy it somewhere on your path:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd galenectl
|
cd skaldctl
|
||||||
go build -ldflags='-s -w'
|
go build -ldflags='-s -w'
|
||||||
sudo cp galenectl /usr/local/bin/
|
sudo cp skaldctl /usr/local/bin/
|
||||||
```
|
```
|
||||||
|
|
||||||
Now create an administrator password, and set up galenectl:
|
Now create an administrator password, and set up skaldctl:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl -admin-username admin initial-setup
|
skaldctl -admin-username admin initial-setup
|
||||||
```
|
```
|
||||||
|
|
||||||
This command creates two files: `galenectl.json` and `config.json`. The
|
This command creates two files: `skaldctl.json` and `config.json`. The
|
||||||
former is already at the right place, the latter must be copied to the
|
former is already at the right place, the latter must be copied to the
|
||||||
server's `data/` directory:
|
server's `data/` directory:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
rsync config.json galene@galene.example.org:data/
|
rsync config.json skald@skald.example.org:data/
|
||||||
```
|
```
|
||||||
|
|
||||||
### Group setup
|
### Group setup
|
||||||
@@ -159,51 +159,51 @@ rsync config.json galene@galene.example.org:data/
|
|||||||
Create a group:
|
Create a group:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl create-group -group city-watch
|
skaldctl create-group -group city-watch
|
||||||
```
|
```
|
||||||
|
|
||||||
If you didn't install a TLS certificate above, you will need to run
|
If you didn't install a TLS certificate above, you will need to run
|
||||||
`galenectl` with the flag `-insecure`:
|
`skaldctl` with the flag `-insecure`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl -insecure create-group -group city-watch
|
skaldctl -insecure create-group -group city-watch
|
||||||
```
|
```
|
||||||
|
|
||||||
Create an "op", a user with group moderation privileges:
|
Create an "op", a user with group moderation privileges:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl create-user -group city-watch -user vimes -permissions op
|
skaldctl create-user -group city-watch -user vimes -permissions op
|
||||||
```
|
```
|
||||||
|
|
||||||
Set the new user's password:
|
Set the new user's password:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl set-password -group city-watch -user vimes
|
skaldctl set-password -group city-watch -user vimes
|
||||||
```
|
```
|
||||||
|
|
||||||
You should now be able to test your Galene installation by pointing a web
|
You should now be able to test your Skald installation by pointing a web
|
||||||
browser at <https://galene.example.org:8443/group/city-watch/>.
|
browser at <https://skald.example.org:8443/group/city-watch/>.
|
||||||
|
|
||||||
Create an ordinary user:
|
Create an ordinary user:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl create-user -group city-watch -user fred
|
skaldctl create-user -group city-watch -user fred
|
||||||
galenectl set-password -group city-watch -user fred
|
skaldctl set-password -group city-watch -user fred
|
||||||
```
|
```
|
||||||
|
|
||||||
Check the results:
|
Check the results:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl list-groups
|
skaldctl list-groups
|
||||||
galenectl list-users -l -group city-watch
|
skaldctl list-users -l -group city-watch
|
||||||
```
|
```
|
||||||
|
|
||||||
Type `galenectl -help`, `galenectl create-group -help`, etc. for more
|
Type `skaldctl -help`, `skaldctl create-group -help`, etc. for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
## Advanced configuration
|
## Advanced configuration
|
||||||
|
|
||||||
Galene is designed to be exposed directly to the Internet. If your server
|
Skald is designed to be exposed directly to the Internet. If your server
|
||||||
is behind a firewall or NAT router, some extra configuration is necessary.
|
is behind a firewall or NAT router, some extra configuration is necessary.
|
||||||
|
|
||||||
### Running behind a firewall
|
### Running behind a firewall
|
||||||
@@ -229,7 +229,7 @@ of the following options:
|
|||||||
and demultiplex the traffic in userspace.
|
and demultiplex the traffic in userspace.
|
||||||
|
|
||||||
At the time of writing, this mechanism is not quite complete, and you will
|
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
|
see Skald attempting to use other ports. Unless you see connection
|
||||||
failures, this is nothing to worry about.
|
failures, this is nothing to worry about.
|
||||||
|
|
||||||
### Running behind NAT
|
### Running behind NAT
|
||||||
@@ -238,23 +238,23 @@ 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
|
a STUN, or, preferably, TURN server on a separate host, one that is not
|
||||||
behind NAT. See Section *Connectivity issues and ICE servers* below.
|
behind NAT. See Section *Connectivity issues and ICE servers* below.
|
||||||
|
|
||||||
Galene has some support for running behind NAT without a helpful server,
|
Skald has some support for running behind NAT without a helpful server,
|
||||||
but this has not been exhaustively tested. Please see the section
|
but this has not been exhaustively tested. Please see the section
|
||||||
"Connectivity issues and ICE servers" below.
|
"Connectivity issues and ICE servers" below.
|
||||||
|
|
||||||
### Running behind a reverse proxy
|
### Running behind a reverse proxy
|
||||||
|
|
||||||
Galene is designed to be directly exposed to the Internet. In order to
|
Skald 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
|
run Skald behind a reverse proxy, you might need to make a number of
|
||||||
tweaks to your configuration.
|
tweaks to your configuration.
|
||||||
|
|
||||||
First, you might need to inform Galene of the URL at which users connect
|
First, you might need to inform Skald of the URL at which users connect
|
||||||
(the reverse proxy's URL) by adding an entry `proxyURL` to your
|
(the reverse proxy's URL) by adding an entry `proxyURL` to your
|
||||||
`data/config.json` file:
|
`data/config.json` file:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"proxyURL": "https://galene.example.org/"
|
"proxyURL": "https://skald.example.org/"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -272,12 +272,12 @@ location /ws {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Finally, in order to avoid TLS termination issues, you may want to run
|
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
|
Skald over plain HTTP instead of HTTPS by using the command-line flag
|
||||||
`-insecure`.
|
`-insecure`.
|
||||||
|
|
||||||
Note that even if you're using a reverse proxy, clients will attempt to
|
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
|
establish direct UDP flows with Skald and direct TCP connections to
|
||||||
Galene's TURN server; see the section *Configuring your firewall*
|
Skald's TURN server; see the section *Configuring your firewall*
|
||||||
above.
|
above.
|
||||||
|
|
||||||
## Connectivity issues and ICE servers
|
## Connectivity issues and ICE servers
|
||||||
@@ -290,7 +290,7 @@ 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
|
serve as relays for traffic. TURN is a superset of STUN: no STUN server
|
||||||
is necessary if one or more TURN servers are available.
|
is necessary if one or more TURN servers are available.
|
||||||
|
|
||||||
Galene includes an IPv4-only TURN server, which is controlled by the
|
Skald includes an IPv4-only TURN server, which is controlled by the
|
||||||
`-turn` command-line option. It has the following behaviour:
|
`-turn` command-line option. It has the following behaviour:
|
||||||
|
|
||||||
* if its value is set to the empty string `""`, then the built-in server
|
* if its value is set to the empty string `""`, then the built-in server
|
||||||
@@ -314,7 +314,7 @@ Galene includes an IPv4-only TURN server, which is controlled by the
|
|||||||
|
|
||||||
If the server is not accessible from the Internet, e.g. because of NAT or
|
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
|
because it is behind a restrictive firewall, then you should configure
|
||||||
a TURN server that runs on a host that is accessible by both Galene and
|
a TURN server that runs on a host that is accessible by both Skald and
|
||||||
the clients. Disable the built-in TURN server (`-turn ""` or the default
|
the clients. Disable the built-in TURN server (`-turn ""` or the default
|
||||||
`-turn auto`), and provide a working ICE configuration in the file
|
`-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
|
`data/ice-servers.json`. In the case of a single STUN server, it should
|
||||||
@@ -340,7 +340,7 @@ look like this:
|
|||||||
"turn:turn.example.org:443",
|
"turn:turn.example.org:443",
|
||||||
"turn:turn.example.org:443?transport=tcp"
|
"turn:turn.example.org:443?transport=tcp"
|
||||||
],
|
],
|
||||||
"username": "galene",
|
"username": "skald",
|
||||||
"credential": "secret"
|
"credential": "secret"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -356,7 +356,7 @@ that, then the `ice-servers.json` file should look like this:
|
|||||||
"turn:turn.example.org:443",
|
"turn:turn.example.org:443",
|
||||||
"turn:turn.example.org:443?transport=tcp"
|
"turn:turn.example.org:443?transport=tcp"
|
||||||
],
|
],
|
||||||
"username": "galene",
|
"username": "skald",
|
||||||
"credential": "secret",
|
"credential": "secret",
|
||||||
"credentialType": "hmac-sha1"
|
"credentialType": "hmac-sha1"
|
||||||
}
|
}
|
||||||
@@ -365,5 +365,5 @@ that, then the `ice-servers.json` file should look like this:
|
|||||||
|
|
||||||
For redundancy, you may set up multiple TURN servers, and ICE will use the
|
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
|
first one that works. If an `ice-servers.json` file is present and
|
||||||
Galene's built-in TURN server is enabled, then the external server will be
|
Skald's built-in TURN server is enabled, then the external server will be
|
||||||
used in preference to the built-in server.
|
used in preference to the built-in server.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Galène's protocol
|
# Skald's protocol
|
||||||
|
|
||||||
## Data structures
|
## Data structures
|
||||||
|
|
||||||
@@ -17,12 +17,12 @@ that do not originate messages (servers) do not need to be assigned an id.
|
|||||||
### Stream
|
### Stream
|
||||||
|
|
||||||
A stream is a set of related tracks. It is identified by an id, an opaque
|
A stream is a set of related tracks. It is identified by an id, an opaque
|
||||||
string. Streams in Galène are unidirectional. A stream is carried by
|
string. Streams in Skald are unidirectional. A stream is carried by
|
||||||
exactly one peer connection (PC) (multiple streams in a single PC are not
|
exactly one peer connection (PC) (multiple streams in a single PC are not
|
||||||
allowed). The offerer is also the RTP sender (i.e. all tracks sent by the
|
allowed). The offerer is also the RTP sender (i.e. all tracks sent by the
|
||||||
offerer are of type `sendonly`).
|
offerer are of type `sendonly`).
|
||||||
|
|
||||||
Galène uses a symmetric, asynchronous protocol. In client-server
|
Skald uses a symmetric, asynchronous protocol. In client-server
|
||||||
usage, some messages are only sent in the client to server or in the
|
usage, some messages are only sent in the client to server or in the
|
||||||
server to client direction.
|
server to client direction.
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ All fields are optional except `name`, `location` and `endpoint`.
|
|||||||
## Connecting
|
## Connecting
|
||||||
|
|
||||||
The client connects to the websocket at the URL obtained at the previous
|
The client connects to the websocket at the URL obtained at the previous
|
||||||
step. Galene uses a symmetric, asynchronous protocol: there are no
|
step. Skald uses a symmetric, asynchronous protocol: there are no
|
||||||
requests and responses, and most messages may be sent by either peer.
|
requests and responses, and most messages may be sent by either peer.
|
||||||
|
|
||||||
## Message syntax
|
## Message syntax
|
||||||
@@ -227,7 +227,7 @@ The field `label` is one of `camera`, `screenshare` or `video`, and will
|
|||||||
be matched against the keys sent by the receiver in their `request` message.
|
be matched against the keys sent by the receiver in their `request` message.
|
||||||
|
|
||||||
The field `sdp` contains the raw SDP string (i.e. the `sdp` field of
|
The field `sdp` contains the raw SDP string (i.e. the `sdp` field of
|
||||||
a JSEP session description). Galène will interpret the `nack`,
|
a JSEP session description). Skald will interpret the `nack`,
|
||||||
`nack pli`, `ccm fir` and `goog-remb` RTCP feedback types, and act
|
`nack pli`, `ccm fir` and `goog-remb` RTCP feedback types, and act
|
||||||
accordingly.
|
accordingly.
|
||||||
|
|
||||||
@@ -541,13 +541,13 @@ receives the `cancel` message immediately tears down the peer connection
|
|||||||
|
|
||||||
# Authorisation protocol
|
# Authorisation protocol
|
||||||
|
|
||||||
In addition to username/password authentication, Galene supports
|
In addition to username/password authentication, Skald supports
|
||||||
authentication using cryptographic tokens. Two flows are supported: using
|
authentication using cryptographic tokens. Two flows are supported: using
|
||||||
an authentication server, where Galene's client requests a token from
|
an authentication server, where Skald's client requests a token from
|
||||||
a third-party server, and using an authentication portal, where
|
a third-party server, and using an authentication portal, where
|
||||||
a third-party login portal redirects the user to Galene. Authentication
|
a third-party login portal redirects the user to Skald. Authentication
|
||||||
servers are somewhat simpler to implement, but authentication portals are
|
servers are somewhat simpler to implement, but authentication portals are
|
||||||
more flexible and avoid communicating the user's password to Galene's
|
more flexible and avoid communicating the user's password to Skald's
|
||||||
Javascript code.
|
Javascript code.
|
||||||
|
|
||||||
## Authentication server
|
## Authentication server
|
||||||
@@ -558,24 +558,24 @@ a POST request to the authorisation server URL containing in its body
|
|||||||
a JSON dictionary of the following form:
|
a JSON dictionary of the following form:
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
"location": "https://galene.example.org/group/groupname/",
|
"location": "https://skald.example.org/group/groupname/",
|
||||||
"username": username,
|
"username": username,
|
||||||
"password": password
|
"password": password
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If the user is not allowed to join the group, then the authorisation
|
If the user is not allowed to join the group, then the authorisation
|
||||||
server replies with a code of 403 ("not authorised"), and Galene will
|
server replies with a code of 403 ("not authorised"), and Skald will
|
||||||
reject the user. If the authentication server has no opinion about
|
reject the user. If the authentication server has no opinion about
|
||||||
whether the user is allowed to join, it replies with a code of 204 ("no
|
whether the user is allowed to join, it replies with a code of 204 ("no
|
||||||
content"), and Galene will proceed with ordinary password authorisation.
|
content"), and Skald will proceed with ordinary password authorisation.
|
||||||
|
|
||||||
If the user is allowed to join, then the authorisation server replies with
|
If the user is allowed to join, then the authorisation server replies with
|
||||||
a signed JWT (a "JWS") the body of which has the following form:
|
a signed JWT (a "JWS") the body of which has the following form:
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
"sub": username,
|
"sub": username,
|
||||||
"aud": "https://galene.example.org/group/groupname/",
|
"aud": "https://skald.example.org/group/groupname/",
|
||||||
"permissions": ["present"],
|
"permissions": ["present"],
|
||||||
"iat": now,
|
"iat": now,
|
||||||
"exp": now + 30s,
|
"exp": now + 30s,
|
||||||
@@ -593,10 +593,10 @@ a stateful token.
|
|||||||
|
|
||||||
## Authentication portal
|
## Authentication portal
|
||||||
|
|
||||||
If a group's status dictionary has a non-empty `authPortal` field, Galene
|
If a group's status dictionary has a non-empty `authPortal` field, Skald
|
||||||
redirects the user agent to the URL indicated by `authPortal`. The
|
redirects the user agent to the URL indicated by `authPortal`. The
|
||||||
authentication portal performs authorisation, generates a token as above,
|
authentication portal performs authorisation, generates a token as above,
|
||||||
then redirects back to the group's URL with the token stores in a URL
|
then redirects back to the group's URL with the token stores in a URL
|
||||||
query parameter named `token`:
|
query parameter named `token`:
|
||||||
|
|
||||||
https://galene.example.org/group/groupname/?token=eyJhbG...
|
https://skald.example.org/group/groupname/?token=eyJhbG...
|
||||||
@@ -14,13 +14,13 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jech/galene/diskwriter"
|
"git.stormux.org/storm/skald/diskwriter"
|
||||||
"github.com/jech/galene/group"
|
"git.stormux.org/storm/skald/group"
|
||||||
"github.com/jech/galene/ice"
|
"git.stormux.org/storm/skald/ice"
|
||||||
"github.com/jech/galene/limit"
|
"git.stormux.org/storm/skald/limit"
|
||||||
"github.com/jech/galene/token"
|
"git.stormux.org/storm/skald/token"
|
||||||
"github.com/jech/galene/turnserver"
|
"git.stormux.org/storm/skald/turnserver"
|
||||||
"github.com/jech/galene/webserver"
|
"git.stormux.org/storm/skald/webserver"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
+59
-59
@@ -1,15 +1,15 @@
|
|||||||
# Galene manual
|
# Skald manual
|
||||||
|
|
||||||
Please see the file [galene-install.md][1] for installation instructions.
|
Please see the file [skald-install.md][1] for installation instructions.
|
||||||
Please see the section *Server administration* below for detailed
|
Please see the section *Server administration* below for detailed
|
||||||
administration instructions.
|
administration instructions.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Galene includes a web server that, by default, listens on port 8443.
|
Skald includes a web server that, by default, listens on port 8443.
|
||||||
Galene is therefore accessed on URLs such as:
|
Skald is therefore accessed on URLs such as:
|
||||||
|
|
||||||
https://galene.example.org:8443/
|
https://skald.example.org:8443/
|
||||||
|
|
||||||
### The landing page
|
### The landing page
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ commands.
|
|||||||
In order to generate an invitation link, choose the entry *Invite user* in
|
In order to generate an invitation link, choose the entry *Invite user* in
|
||||||
the group menu. This generates a link of the form
|
the group menu. This generates a link of the form
|
||||||
|
|
||||||
https://galene.example.org:8443/group/city-watch/?token=XXX
|
https://skald.example.org:8443/group/city-watch/?token=XXX
|
||||||
|
|
||||||
where the *XXX* part, known as the *token*, is a shared secret. Such
|
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
|
a link allows password-less login to the group, and may therefore be
|
||||||
@@ -102,7 +102,7 @@ Tokens can be created, modified, and expired using the `/invite`,
|
|||||||
|
|
||||||
### File transfer
|
### File transfer
|
||||||
|
|
||||||
Galene includes a peer-to-peer, end-to-end encrypted file transfer protocol.
|
Skald includes a peer-to-peer, end-to-end encrypted file transfer protocol.
|
||||||
In order to transfer a file, click on the receiver's entry in the user
|
In order to transfer a file, click on the receiver's entry in the user
|
||||||
list and choose *Send file*.
|
list and choose *Send file*.
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ file may look as follows:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"users":{"vetinari": {"password":"lagniappe", "permissions": "admin"}},
|
"users":{"vetinari": {"password":"lagniappe", "permissions": "admin"}},
|
||||||
"canonicalHost": "galene.example.org",
|
"canonicalHost": "skald.example.org",
|
||||||
"writableGroups": true
|
"writableGroups": true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -146,12 +146,12 @@ or, better, with a hashed password:
|
|||||||
"permissions": "admin"
|
"permissions": "admin"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"canonicalHost": "galene.example.org",
|
"canonicalHost": "skald.example.org",
|
||||||
"writableGroups": true
|
"writableGroups": true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The file is initially created using `galenectl initial-setup`, but may be
|
The file is initially created using `skaldctl initial-setup`, but may be
|
||||||
manually edited at any time (there is no need to restart the server). The
|
manually edited at any time (there is no need to restart the server). The
|
||||||
fields are as follows:
|
fields are as follows:
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ fields are as follows:
|
|||||||
same syntax as user definitions in groups (see below), except that the
|
same syntax as user definitions in groups (see below), except that the
|
||||||
only meaningful permission is `"admin"`;
|
only meaningful permission is `"admin"`;
|
||||||
|
|
||||||
- `writableGroups`: if true, then the API used by `galenectl` can be used
|
- `writableGroups`: if true, then the API used by `skaldctl` can be used
|
||||||
to modify group definitions; if unset or false, then only read-only
|
to modify group definitions; if unset or false, then only read-only
|
||||||
access is allowed;
|
access is allowed;
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ fields are as follows:
|
|||||||
are allowed to access the server;
|
are allowed to access the server;
|
||||||
|
|
||||||
- `allowAdminOrigin` is like `allowOrigin`, but applies to the
|
- `allowAdminOrigin` is like `allowOrigin`, but applies to the
|
||||||
administrative API (the one used by `galenectl`);
|
administrative API (the one used by `skaldctl`);
|
||||||
|
|
||||||
- `proxyURL`: if running behind a reverse proxy, this specifies the root
|
- `proxyURL`: if running behind a reverse proxy, this specifies the root
|
||||||
URL that will be visible outside the proxy;
|
URL that will be visible outside the proxy;
|
||||||
@@ -180,28 +180,28 @@ fields are as follows:
|
|||||||
## Group definitions
|
## Group definitions
|
||||||
|
|
||||||
Groups are described by JSON files in the `groups/` directory. These
|
Groups are described by JSON files in the `groups/` directory. These
|
||||||
files are normally administered using the `galenectl` utility, but may
|
files are normally administered using the `skaldctl` utility, but may
|
||||||
also be edited manually (there is no need to restart the server).
|
also be edited manually (there is no need to restart the server).
|
||||||
|
|
||||||
### Managing groups using `galenectl`
|
### Managing groups using `skaldctl`
|
||||||
|
|
||||||
#### Creating, modifying, and deleting groups
|
#### Creating, modifying, and deleting groups
|
||||||
|
|
||||||
A group is created using `galenectl create-group`:
|
A group is created using `skaldctl create-group`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl create-group -group city-watch
|
skaldctl create-group -group city-watch
|
||||||
```
|
```
|
||||||
|
|
||||||
There are a number of options to customise the behaviour of the group, see
|
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
|
`skaldctl create-group -help` for a full list. For example, in order to
|
||||||
create a group that allows unrestricted creation of tokens, say:
|
create a group that allows unrestricted creation of tokens, say:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl create-group -group city-watch -unrestricted-tokens
|
skaldctl create-group -group city-watch -unrestricted-tokens
|
||||||
```
|
```
|
||||||
|
|
||||||
For more advanced configuration, `galenectl create-group` can be invoked
|
For more advanced configuration, `skaldctl create-group` can be invoked
|
||||||
with the `-json` flag, in which case it takes a JSON template from standard
|
with the `-json` flag, in which case it takes a JSON template from standard
|
||||||
input. The syntax of a JSON template is just like that of a group
|
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
|
definition file (see below), except that it must not contain the fields
|
||||||
@@ -209,35 +209,35 @@ definition file (see below), except that it must not contain the fields
|
|||||||
(see the section *Group description reference* below):
|
(see the section *Group description reference* below):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
echo '{"redirect": "https://galene.example.org:8443/group/city-watch/"}' | galenectl create-group -group amcw -json
|
echo '{"redirect": "https://skald.example.org:8443/group/city-watch/"}' | skaldctl create-group -group amcw -json
|
||||||
```
|
```
|
||||||
|
|
||||||
Groups are modified using `galenectl update-group`:
|
Groups are modified using `skaldctl update-group`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl update-group -group city-watch -unrestricted-tokens=false
|
skaldctl update-group -group city-watch -unrestricted-tokens=false
|
||||||
```
|
```
|
||||||
|
|
||||||
If a JSON template is provided to `galenectl update-group`, then it is
|
If a JSON template is provided to `skaldctl update-group`, then it is
|
||||||
merged with the existing group configuration. Entries may be deleted
|
merged with the existing group configuration. Entries may be deleted
|
||||||
by setting them to `null` in the template:
|
by setting them to `null` in the template:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
echo '{"redirect": null}' | galenectl update-group -group amcw
|
echo '{"redirect": null}' | skaldctl update-group -group amcw
|
||||||
```
|
```
|
||||||
|
|
||||||
A group is deleted using `galenectl delete-group`:
|
A group is deleted using `skaldctl delete-group`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl delete-group -group amcw
|
skaldctl delete-group -group amcw
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Creating, modifying, and deleting users
|
#### Creating, modifying, and deleting users
|
||||||
|
|
||||||
A user entry is created with the `galenectl create-user` command:
|
A user entry is created with the `skaldctl create-user` command:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl create-user -group city-watch -user vimes -permissions op
|
skaldctl create-user -group city-watch -user vimes -permissions op
|
||||||
```
|
```
|
||||||
|
|
||||||
If the `-permissions` flag is not specified, it defaults to `present`,
|
If the `-permissions` flag is not specified, it defaults to `present`,
|
||||||
@@ -246,14 +246,14 @@ the group. Other useful values are `message`, which allows a user
|
|||||||
to participate in the chat only, and `observe`, which doesn't allow any
|
to participate in the chat only, and `observe`, which doesn't allow any
|
||||||
active participation.
|
active participation.
|
||||||
|
|
||||||
A user is modified using `galenectl update-user`, and deleted using
|
A user is modified using `skaldctl update-user`, and deleted using
|
||||||
`galenectl delete-user`.
|
`skaldctl delete-user`.
|
||||||
|
|
||||||
In order to be useful, a user entry needs to be assigned a password. This
|
In order to be useful, a user entry needs to be assigned a password. This
|
||||||
is done with the `galenectl set-password` command:
|
is done with the `skaldctl set-password` command:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl set-password -group city-watch -user vimes
|
skaldctl set-password -group city-watch -user vimes
|
||||||
```
|
```
|
||||||
|
|
||||||
#### The fallback user
|
#### The fallback user
|
||||||
@@ -262,15 +262,15 @@ It is sometimes useful to allow multiple users to log in using the same
|
|||||||
password. This can be achieved by defining the *wildcard* user:
|
password. This can be achieved by defining the *wildcard* user:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl create-user -group city-watch -wildcard
|
skaldctl create-user -group city-watch -wildcard
|
||||||
galenectl set-password -group city-watch -wildcard
|
skaldctl set-password -group city-watch -wildcard
|
||||||
```
|
```
|
||||||
|
|
||||||
For open groups, where any user can login with any password, the 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`:
|
user's password is set to the password of type `wildcard`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl set-password -group city-watch -wildcard -type wildcard
|
skaldctl set-password -group city-watch -wildcard -type wildcard
|
||||||
```
|
```
|
||||||
|
|
||||||
See the section *Client authorisation* below for more information about
|
See the section *Client authorisation* below for more information about
|
||||||
@@ -279,19 +279,19 @@ password types.
|
|||||||
#### Automatic subgroups
|
#### Automatic subgroups
|
||||||
|
|
||||||
It is sometimes necessary to create a large number of identical groups.
|
It is sometimes necessary to create a large number of identical groups.
|
||||||
For example, the author has been using Galene to supervise computer
|
For example, the author has been using Skald to supervise computer
|
||||||
science practicals, where up to 40 students are working in groups of two.
|
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
|
While it is possible to automate the creation of groups by accessing
|
||||||
Galene's API, by scripting calls to galenectl, or by generating files
|
Skald's API, by scripting calls to skaldctl, or by generating files
|
||||||
directly under `groups/`, Galene provides a facility called *automatic
|
directly under `groups/`, Skald provides a facility called *automatic
|
||||||
subgroups* that can be used to generate groups on demand.
|
subgroups* that can be used to generate groups on demand.
|
||||||
|
|
||||||
Automatic subgroups are enabled by setting the `"auto-subgroups"`
|
Automatic subgroups are enabled by setting the `"auto-subgroups"`
|
||||||
field in the group description:
|
field in the group description:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl create-group unseen-university -auto-subgroups
|
skaldctl create-group unseen-university -auto-subgroups
|
||||||
```
|
```
|
||||||
|
|
||||||
Whenever a user attempts to access a subgroup of `unseen-university`, for
|
Whenever a user attempts to access a subgroup of `unseen-university`, for
|
||||||
@@ -303,13 +303,13 @@ group's operator can view the list of populated subgroups with the command
|
|||||||
#### Managing tokens
|
#### Managing tokens
|
||||||
|
|
||||||
Tokens are normally managed using the `/invite`, `/reinvite`, and `/expire`
|
Tokens are normally managed using the `/invite`, `/reinvite`, and `/expire`
|
||||||
commands in Galene's user interface, but they may also be managed using
|
commands in Skald's user interface, but they may also be managed using
|
||||||
the `galenectl` utility's `create-token`, `revoke-token`, `delete-token`
|
the `skaldctl` utility's `create-token`, `revoke-token`, `delete-token`
|
||||||
and `list-tokens` commands:
|
and `list-tokens` commands:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl create-token -group city-watch
|
skaldctl create-token -group city-watch
|
||||||
galenectl list-tokens -l -group city-watch
|
skaldctl list-tokens -l -group city-watch
|
||||||
```
|
```
|
||||||
|
|
||||||
A token that is generated with the `-include-subgroups` flag applies to
|
A token that is generated with the `-include-subgroups` flag applies to
|
||||||
@@ -317,14 +317,14 @@ the whole hierarchy rooted at the given group, including both ordinary
|
|||||||
groups and automatically generated subgroups.
|
groups and automatically generated subgroups.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl create-token -group city-watch -include-subgroups
|
skaldctl create-token -group city-watch -include-subgroups
|
||||||
```
|
```
|
||||||
|
|
||||||
Such a token can be attached to the root of the group hierarchy, and
|
Such a token can be attached to the root of the group hierarchy, and
|
||||||
therefore be valid for any group on the server:
|
therefore be valid for any group on the server:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
galenectl create-token -group '' -include-subgroups
|
skaldctl create-token -group '' -include-subgroups
|
||||||
```
|
```
|
||||||
|
|
||||||
### Group description reference
|
### Group description reference
|
||||||
@@ -393,7 +393,7 @@ are optional. The following fields are allowed:
|
|||||||
|
|
||||||
A user definition is a dictionary with entries `password` and
|
A user definition is a dictionary with entries `password` and
|
||||||
`permission`. The value of the `password` field is either a plaintext
|
`permission`. The value of the `password` field is either a plaintext
|
||||||
password, or a hashed password generated for example by the `galenectl
|
password, or a hashed password generated for example by the `skaldctl
|
||||||
hash-password` command. The value of the `permissions` field can either
|
hash-password` command. The value of the `permissions` field can either
|
||||||
be an array of individual permissions (not recommended), or one of the
|
be an array of individual permissions (not recommended), or one of the
|
||||||
following strings:
|
following strings:
|
||||||
@@ -425,7 +425,7 @@ anything except Opus.
|
|||||||
|
|
||||||
## Client Authorisation
|
## Client Authorisation
|
||||||
|
|
||||||
Galene implements three authorisation methods: a username/password
|
Skald implements three authorisation methods: a username/password
|
||||||
authorisation scheme, a scheme using stateful tokens, and a mechanism
|
authorisation scheme, a scheme using stateful tokens, and a mechanism
|
||||||
based on cryptographic tokens. The former two mechanisms are intended to
|
based on cryptographic tokens. The former two mechanisms are intended to
|
||||||
be used in standalone installations, while the cryptographic mechanism is
|
be used in standalone installations, while the cryptographic mechanism is
|
||||||
@@ -439,13 +439,13 @@ defined directly in the group configuration file, in the `users` and
|
|||||||
`wildcard-user` entries. The `users` entry is a dictionary that maps user
|
`wildcard-user` entries. The `users` entry is a dictionary that maps user
|
||||||
names to user descriptions; the `wildcard-user` is a user description
|
names to user descriptions; the `wildcard-user` is a user description
|
||||||
that is used with usernames that don't appear in `users`. These two
|
that is used with usernames that don't appear in `users`. These two
|
||||||
entries are usually managed by the `galenectl` utility.
|
entries are usually managed by the `skaldctl` utility.
|
||||||
|
|
||||||
Every user description is a dictionary with fields `password` and
|
Every user description is a dictionary with fields `password` and
|
||||||
`permissions`. The `password` field may be a literal password string, or
|
`permissions`. The `password` field may be a literal password string, or
|
||||||
a dictionary describing a hashed password or a wildcard. The
|
a dictionary describing a hashed password or a wildcard. The
|
||||||
`permissions` field should be one of `op`, `present`, `message` or
|
`permissions` field should be one of `op`, `present`, `message` or
|
||||||
`observe`. (An array of Galene's internal permissions is also allowed,
|
`observe`. (An array of Skald's internal permissions is also allowed,
|
||||||
but this is not recommended, since internal permissions may vary from
|
but this is not recommended, since internal permissions may vary from
|
||||||
version to version.)
|
version to version.)
|
||||||
|
|
||||||
@@ -479,7 +479,7 @@ allows any username with any password.
|
|||||||
### Hashed passwords
|
### Hashed passwords
|
||||||
|
|
||||||
For security reasons, passwords are usually hashed before being stored in
|
For security reasons, passwords are usually hashed before being stored in
|
||||||
group descriptions (in fact, the `galenectl` utility does not even support
|
group descriptions (in fact, the `skaldctl` utility does not even support
|
||||||
storing plaintext passwords). A hashed password is represented as a JSON
|
storing plaintext passwords). A hashed password is represented as a JSON
|
||||||
dictionary with a field `type` and a number of type-specific fields.
|
dictionary with a field `type` and a number of type-specific fields.
|
||||||
|
|
||||||
@@ -501,14 +501,14 @@ A user entry with a hashed password looks like this:
|
|||||||
```
|
```
|
||||||
|
|
||||||
Hashed passwords are normally generated transparently to the user by the
|
Hashed passwords are normally generated transparently to the user by the
|
||||||
`galenectl set-password` command. When editing group description files
|
`skaldctl set-password` command. When editing group description files
|
||||||
manually, hashed passwords can be generated with the `galenectl hash-password`
|
manually, hashed passwords can be generated with the `skaldctl hash-password`
|
||||||
utility.
|
utility.
|
||||||
|
|
||||||
### Stateful tokens
|
### Stateful tokens
|
||||||
|
|
||||||
Stateful tokens are created by the `/invite` command in the Galene user
|
Stateful tokens are created by the `/invite` command in the Skald user
|
||||||
interface or by the `galenectl create-token` command; see the section
|
interface or by the `skaldctl create-token` command; see the section
|
||||||
*Managing tokens* above. They are stored in the file
|
*Managing tokens* above. They are stored in the file
|
||||||
`data/var/tokens.jsonl`, which, on most filesystems, can be safely backed
|
`data/var/tokens.jsonl`, which, on most filesystems, can be safely backed
|
||||||
up without stopping the server.
|
up without stopping the server.
|
||||||
@@ -516,7 +516,7 @@ up without stopping the server.
|
|||||||
### Cryptographic tokens
|
### Cryptographic tokens
|
||||||
|
|
||||||
In many cases, it is useful to delegate authorisation decisions to a third
|
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
|
party, such as an LDAP or OAuth2 client. Skald implements delegation of
|
||||||
authorisation decisions using cryptographic tokens generated by a third
|
authorisation decisions using cryptographic tokens generated by a third
|
||||||
party known as an *authorisation server*. Two authorisation servers are
|
party known as an *authorisation server*. Two authorisation servers are
|
||||||
available: an [LDAP client][2], and a [sample server written in Python][3].
|
available: an [LDAP client][2], and a [sample server written in Python][3].
|
||||||
@@ -564,9 +564,9 @@ Alternatively, the group file may specify an authorisation portal using
|
|||||||
the `"authPortal"` key. If an authorisation portal is specified, then the
|
the `"authPortal"` key. If an authorisation portal is specified, then the
|
||||||
default client will redirect initial client connections to the
|
default client will redirect initial client connections to the
|
||||||
authorisation portal. The authorisation portal is expected to authorise
|
authorisation portal. The authorisation portal is expected to authorise
|
||||||
the client and then redirect it to Galene with the `username` and `token`
|
the client and then redirect it to Skald with the `username` and `token`
|
||||||
query parameters set.
|
query parameters set.
|
||||||
|
|
||||||
[1]: <galene-install.md>
|
[1]: <skald-install.md>
|
||||||
[2]: <https://github.com/jech/galene-imap/>
|
[2]: <https://git.stormux.org/storm/skald-imap/>
|
||||||
[3]: <https://github.com/jech/galene-sample-auth-server/>
|
[3]: <https://git.stormux.org/storm/skald-sample-auth-server/>
|
||||||
@@ -26,8 +26,8 @@ import (
|
|||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
|
|
||||||
"github.com/jech/galene/group"
|
"git.stormux.org/storm/skald/group"
|
||||||
"github.com/jech/galene/token"
|
"git.stormux.org/storm/skald/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
type configuration struct {
|
type configuration struct {
|
||||||
@@ -55,7 +55,7 @@ var commands = map[string]command{
|
|||||||
},
|
},
|
||||||
"initial-setup": {
|
"initial-setup": {
|
||||||
command: initialSetupCmd,
|
command: initialSetupCmd,
|
||||||
description: "initial setup of Galene and galenectl",
|
description: "initial setup of Skald and skaldctl",
|
||||||
},
|
},
|
||||||
"set-password": {
|
"set-password": {
|
||||||
command: setPasswordCmd,
|
command: setPasswordCmd,
|
||||||
@@ -125,8 +125,8 @@ func main() {
|
|||||||
log.Fatalf("UserConfigDir: %v", err)
|
log.Fatalf("UserConfigDir: %v", err)
|
||||||
}
|
}
|
||||||
configFile = filepath.Join(
|
configFile = filepath.Join(
|
||||||
filepath.Join(configdir, "galene"),
|
filepath.Join(configdir, "skald"),
|
||||||
"galenectl.json",
|
"skaldctl.json",
|
||||||
)
|
)
|
||||||
|
|
||||||
flag.Usage = func() {
|
flag.Usage = func() {
|
||||||
@@ -332,15 +332,15 @@ func hashPasswordCmd(cmdname string, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initialSetupCmd(cmdname string, args []string) {
|
func initialSetupCmd(cmdname string, args []string) {
|
||||||
var galeneConfigFn string
|
var skaldConfigFn string
|
||||||
|
|
||||||
cmd := flag.NewFlagSet(cmdname, flag.ExitOnError)
|
cmd := flag.NewFlagSet(cmdname, flag.ExitOnError)
|
||||||
setUsage(cmd, cmdname,
|
setUsage(cmd, cmdname,
|
||||||
"%v [option...] %v [option...]\n",
|
"%v [option...] %v [option...]\n",
|
||||||
os.Args[0], cmdname,
|
os.Args[0], cmdname,
|
||||||
)
|
)
|
||||||
cmd.StringVar(&galeneConfigFn, "config", "config.json",
|
cmd.StringVar(&skaldConfigFn, "config", "config.json",
|
||||||
"Galene configuration `file`")
|
"Skald configuration `file`")
|
||||||
cmd.Parse(args)
|
cmd.Parse(args)
|
||||||
|
|
||||||
if cmd.NArg() != 0 {
|
if cmd.NArg() != 0 {
|
||||||
@@ -373,24 +373,24 @@ func initialSetupCmd(cmdname string, args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
galeneConfig, err := os.OpenFile(galeneConfigFn,
|
skaldConfig, err := os.OpenFile(skaldConfigFn,
|
||||||
os.O_WRONLY|os.O_CREATE|os.O_CREATE|os.O_EXCL,
|
os.O_WRONLY|os.O_CREATE|os.O_CREATE|os.O_EXCL,
|
||||||
0600)
|
0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Create %v: %v", galeneConfigFn, err)
|
log.Fatalf("Create %v: %v", skaldConfigFn, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
galenectlConfig, err := os.OpenFile(configFile,
|
skaldctlConfig, err := os.OpenFile(configFile,
|
||||||
os.O_WRONLY|os.O_CREATE|os.O_CREATE|os.O_EXCL,
|
os.O_WRONLY|os.O_CREATE|os.O_CREATE|os.O_EXCL,
|
||||||
0600)
|
0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
galeneConfig.Close()
|
skaldConfig.Close()
|
||||||
os.Remove(galeneConfigFn)
|
os.Remove(skaldConfigFn)
|
||||||
log.Fatalf("Create %v: %v", galeneConfigFn, err)
|
log.Fatalf("Create %v: %v", skaldConfigFn, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer galeneConfig.Close()
|
defer skaldConfig.Close()
|
||||||
defer galenectlConfig.Close()
|
defer skaldctlConfig.Close()
|
||||||
|
|
||||||
var users map[string]group.UserDescription
|
var users map[string]group.UserDescription
|
||||||
if adminPassword != "" {
|
if adminPassword != "" {
|
||||||
@@ -416,11 +416,11 @@ func initialSetupCmd(cmdname string, args []string) {
|
|||||||
Users: users,
|
Users: users,
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder := json.NewEncoder(galeneConfig)
|
encoder := json.NewEncoder(skaldConfig)
|
||||||
encoder.SetIndent("", " ")
|
encoder.SetIndent("", " ")
|
||||||
err = encoder.Encode(&config)
|
err = encoder.Encode(&config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Encode %v: %v", galeneConfigFn, err)
|
log.Fatalf("Encode %v: %v", skaldConfigFn, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctlConfig := configuration{
|
ctlConfig := configuration{
|
||||||
@@ -430,14 +430,14 @@ func initialSetupCmd(cmdname string, args []string) {
|
|||||||
AdminToken: adminToken,
|
AdminToken: adminToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctlEncoder := json.NewEncoder(galenectlConfig)
|
ctlEncoder := json.NewEncoder(skaldctlConfig)
|
||||||
ctlEncoder.SetIndent("", " ")
|
ctlEncoder.SetIndent("", " ")
|
||||||
err = ctlEncoder.Encode(&ctlConfig)
|
err = ctlEncoder.Encode(&ctlConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Encode %v: %v", configFile, err)
|
log.Fatalf("Encode %v: %v", configFile, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("The file %v has been created. ", galeneConfigFn)
|
fmt.Printf("The file %v has been created. ", skaldConfigFn)
|
||||||
fmt.Printf("Please copy it into your server's\n\"data/\" directory.\n")
|
fmt.Printf("Please copy it into your server's\n\"data/\" directory.\n")
|
||||||
fmt.Printf("The file %v has been created. ", configFile)
|
fmt.Printf("The file %v has been created. ", configFile)
|
||||||
fmt.Printf("It contains the administrator's\npassword in cleartext, ")
|
fmt.Printf("It contains the administrator's\npassword in cleartext, ")
|
||||||
@@ -655,12 +655,12 @@ func setPasswordCmd(cmdname string, args []string) {
|
|||||||
var u string
|
var u string
|
||||||
if wildcard {
|
if wildcard {
|
||||||
u, err = url.JoinPath(
|
u, err = url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups", groupname,
|
serverURL, "/skald-api/v0/.groups", groupname,
|
||||||
".wildcard-user/.password",
|
".wildcard-user/.password",
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
u, err = url.JoinPath(
|
u, err = url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups", groupname,
|
serverURL, "/skald-api/v0/.groups", groupname,
|
||||||
".users", username, ".password",
|
".users", username, ".password",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -710,12 +710,12 @@ func deletePasswordCmd(cmdname string, args []string) {
|
|||||||
var err error
|
var err error
|
||||||
if wildcard {
|
if wildcard {
|
||||||
u, err = url.JoinPath(
|
u, err = url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups", groupname,
|
serverURL, "/skald-api/v0/.groups", groupname,
|
||||||
".wildcard-user/.password",
|
".wildcard-user/.password",
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
u, err = url.JoinPath(
|
u, err = url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups", groupname,
|
serverURL, "/skald-api/v0/.groups", groupname,
|
||||||
".users", username, ".password",
|
".users", username, ".password",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -828,7 +828,7 @@ func createGroupCmd(cmdname string, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.JoinPath(
|
u, err := url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups", groupname,
|
serverURL, "/skald-api/v0/.groups", groupname,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Build URL: %v", err)
|
log.Fatalf("Build URL: %v", err)
|
||||||
@@ -874,7 +874,7 @@ func deleteGroupCmd(cmdname string, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.JoinPath(
|
u, err := url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups", groupname,
|
serverURL, "/skald-api/v0/.groups", groupname,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Build URL: %v", err)
|
log.Fatalf("Build URL: %v", err)
|
||||||
@@ -913,7 +913,7 @@ func updateGroupCmd(cmdname string, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.JoinPath(
|
u, err := url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups", groupname,
|
serverURL, "/skald-api/v0/.groups", groupname,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Build URL: %v", err)
|
log.Fatalf("Build URL: %v", err)
|
||||||
@@ -1025,7 +1025,7 @@ func listUsersCmd(cmdname string, args []string) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.JoinPath(serverURL, "/galene-api/v0/.groups/", groupname,
|
u, err := url.JoinPath(serverURL, "/skald-api/v0/.groups/", groupname,
|
||||||
".users/")
|
".users/")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Build URL: %v", err)
|
log.Fatalf("Build URL: %v", err)
|
||||||
@@ -1072,12 +1072,12 @@ func listUsersCmd(cmdname string, args []string) {
|
|||||||
func userURL(wildcard bool, groupname, username string) (string, error) {
|
func userURL(wildcard bool, groupname, username string) (string, error) {
|
||||||
if wildcard {
|
if wildcard {
|
||||||
return url.JoinPath(
|
return url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups", groupname,
|
serverURL, "/skald-api/v0/.groups", groupname,
|
||||||
".wildcard-user",
|
".wildcard-user",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return url.JoinPath(
|
return url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups", groupname,
|
serverURL, "/skald-api/v0/.groups", groupname,
|
||||||
".users", username,
|
".users", username,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1250,12 +1250,12 @@ func deleteUserCmd(cmdname string, args []string) {
|
|||||||
var err error
|
var err error
|
||||||
if wildcard {
|
if wildcard {
|
||||||
u, err = url.JoinPath(
|
u, err = url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups", groupname,
|
serverURL, "/skald-api/v0/.groups", groupname,
|
||||||
".wildcard-user",
|
".wildcard-user",
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
u, err = url.JoinPath(
|
u, err = url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups", groupname,
|
serverURL, "/skald-api/v0/.groups", groupname,
|
||||||
".users", username,
|
".users", username,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1288,7 +1288,7 @@ func showGroupCmd(cmdname string, args []string) {
|
|||||||
log.Fatal("Option \"-group\" is required.")
|
log.Fatal("Option \"-group\" is required.")
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.JoinPath(serverURL, "/galene-api/v0/.groups/", groupname)
|
u, err := url.JoinPath(serverURL, "/skald-api/v0/.groups/", groupname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Build URL: %v", err)
|
log.Fatalf("Build URL: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1315,7 +1315,7 @@ func listGroupsCmd(cmdname string, args []string) {
|
|||||||
cmd.Parse(args)
|
cmd.Parse(args)
|
||||||
patterns := cmd.Args()
|
patterns := cmd.Args()
|
||||||
|
|
||||||
u, err := url.JoinPath(serverURL, "/galene-api/v0/.groups/")
|
u, err := url.JoinPath(serverURL, "/skald-api/v0/.groups/")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Build URL: %v", err)
|
log.Fatalf("Build URL: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1365,7 +1365,7 @@ func listTokensCmd(cmdname string, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.JoinPath(
|
u, err := url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups/", groupname.value, ".tokens/",
|
serverURL, "/skald-api/v0/.groups/", groupname.value, ".tokens/",
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1469,7 +1469,7 @@ func createTokenCmd(cmdname string, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.JoinPath(
|
u, err := url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups/", groupname.value, ".tokens/",
|
serverURL, "/skald-api/v0/.groups/", groupname.value, ".tokens/",
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Build URL: %v", err)
|
log.Fatalf("Build URL: %v", err)
|
||||||
@@ -1505,7 +1505,7 @@ func revokeTokenCmd(cmdname string, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.JoinPath(
|
u, err := url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups/", groupname.value,
|
serverURL, "/skald-api/v0/.groups/", groupname.value,
|
||||||
".tokens", token,
|
".tokens", token,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1544,7 +1544,7 @@ func deleteTokenCmd(cmdname string, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.JoinPath(
|
u, err := url.JoinPath(
|
||||||
serverURL, "/galene-api/v0/.groups/", groupname.value,
|
serverURL, "/skald-api/v0/.groups/", groupname.value,
|
||||||
".tokens", token,
|
".tokens", token,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jech/galene/group"
|
"git.stormux.org/storm/skald/group"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMakePassword(t *testing.T) {
|
func TestMakePassword(t *testing.T) {
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="/common.css">
|
<link rel="stylesheet" href="/common.css">
|
||||||
<link rel="stylesheet" href="/change-password.css">
|
<link rel="stylesheet" href="/change-password.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/galene.css"/>
|
<link rel="stylesheet" type="text/css" href="/skald.css"/>
|
||||||
<link rel="author" href="https://www.irif.fr/~jch/"/>
|
<link rel="author" href="https://www.irif.fr/~jch/"/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Galène client example</title>
|
<title>Skald client example</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="author" href="https://www.irif.fr/~jch/"/>
|
<link rel="author" href="https://www.irif.fr/~jch/"/>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Galene client example. */
|
/* Skald client example. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main function.
|
* The main function.
|
||||||
|
|||||||
+4
-4
@@ -1,19 +1,19 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Galène</title>
|
<title>Skald</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="/common.css">
|
<link rel="stylesheet" href="/common.css">
|
||||||
<link rel="stylesheet" href="/mainpage.css">
|
<link rel="stylesheet" href="/mainpage.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/galene.css"/>
|
<link rel="stylesheet" type="text/css" href="/skald.css"/>
|
||||||
<link rel="author" href="https://www.irif.fr/~jch/"/>
|
<link rel="author" href="https://www.irif.fr/~jch/"/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="home">
|
<div class="home">
|
||||||
<h1 id="title" class="navbar-brand">Galène</h1>
|
<h1 id="title" class="navbar-brand">Skald</h1>
|
||||||
|
|
||||||
<form id="groupform">
|
<form id="groupform">
|
||||||
<label for="group">Group:</label>
|
<label for="group">Group:</label>
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer class="signature">
|
<footer class="signature">
|
||||||
<p><a href="https://galene.org/">Galène</a> by <a href="https://www.irif.fr/~jch/" rel="author">Juliusz Chroboczek</a></p>
|
<p><a href="https://skald.org/">Skald</a> by <a href="https://www.irif.fr/~jch/" rel="author">Juliusz Chroboczek</a></p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="/mainpage.js" defer></script>
|
<script src="/mainpage.js" defer></script>
|
||||||
|
|||||||
+13
-13
@@ -159,7 +159,7 @@ async function updateObject(url, values, etag) {
|
|||||||
* @returns {Promise<Array<string>>}
|
* @returns {Promise<Array<string>>}
|
||||||
*/
|
*/
|
||||||
async function listGroups() {
|
async function listGroups() {
|
||||||
return await listObjects('/galene-api/v0/.groups/');
|
return await listObjects('/skald-api/v0/.groups/');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -170,7 +170,7 @@ async function listGroups() {
|
|||||||
* @returns {Promise<Object>}
|
* @returns {Promise<Object>}
|
||||||
*/
|
*/
|
||||||
async function getGroup(group, etag) {
|
async function getGroup(group, etag) {
|
||||||
return await getObject(`/galene-api/v0/.groups/${group}`, etag);
|
return await getObject(`/skald-api/v0/.groups/${group}`, etag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,7 +180,7 @@ async function getGroup(group, etag) {
|
|||||||
* @param {Object} [values]
|
* @param {Object} [values]
|
||||||
*/
|
*/
|
||||||
async function createGroup(group, values) {
|
async function createGroup(group, values) {
|
||||||
return await createObject(`/galene-api/v0/.groups/${group}`, values);
|
return await createObject(`/skald-api/v0/.groups/${group}`, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -190,7 +190,7 @@ async function createGroup(group, values) {
|
|||||||
* @param {string} [etag]
|
* @param {string} [etag]
|
||||||
*/
|
*/
|
||||||
async function deleteGroup(group, etag) {
|
async function deleteGroup(group, etag) {
|
||||||
return await deleteObject(`/galene-api/v0/.groups/${group}`, etag);
|
return await deleteObject(`/skald-api/v0/.groups/${group}`, etag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -203,7 +203,7 @@ async function deleteGroup(group, etag) {
|
|||||||
* @param {string} [etag]
|
* @param {string} [etag]
|
||||||
*/
|
*/
|
||||||
async function updateGroup(group, values, etag) {
|
async function updateGroup(group, values, etag) {
|
||||||
return await updateObject(`/galene-api/v0/.groups/${group}`, values);
|
return await updateObject(`/skald-api/v0/.groups/${group}`, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -213,7 +213,7 @@ async function updateGroup(group, values, etag) {
|
|||||||
* @returns {Promise<Array<string>>}
|
* @returns {Promise<Array<string>>}
|
||||||
*/
|
*/
|
||||||
async function listUsers(group) {
|
async function listUsers(group) {
|
||||||
return await listObjects(`/galene-api/v0/.groups/${group}/.users/`);
|
return await listObjects(`/skald-api/v0/.groups/${group}/.users/`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -225,11 +225,11 @@ async function listUsers(group) {
|
|||||||
*/
|
*/
|
||||||
function userURL(group, user, wildcard) {
|
function userURL(group, user, wildcard) {
|
||||||
if(wildcard)
|
if(wildcard)
|
||||||
return `/galene-api/v0/.groups/${group}/.wildcard-user`;
|
return `/skald-api/v0/.groups/${group}/.wildcard-user`;
|
||||||
else if(user === "")
|
else if(user === "")
|
||||||
return `/galene-api/v0/.groups/${group}/.empty-user`;
|
return `/skald-api/v0/.groups/${group}/.empty-user`;
|
||||||
else
|
else
|
||||||
return `/galene-api/v0/.groups/${group}/.users/${user}`
|
return `/skald-api/v0/.groups/${group}/.users/${user}`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -320,7 +320,7 @@ async function setPassword(group, user, wildcard, password, oldpassword) {
|
|||||||
* @returns {Promise<Array<string>>}
|
* @returns {Promise<Array<string>>}
|
||||||
*/
|
*/
|
||||||
async function listTokens(group) {
|
async function listTokens(group) {
|
||||||
return await listObjects(`/galene-api/v0/.groups/${group}/.tokens/`);
|
return await listObjects(`/skald-api/v0/.groups/${group}/.tokens/`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -332,7 +332,7 @@ async function listTokens(group) {
|
|||||||
* @returns {Promise<Object>}
|
* @returns {Promise<Object>}
|
||||||
*/
|
*/
|
||||||
async function getToken(group, token, etag) {
|
async function getToken(group, token, etag) {
|
||||||
return await getObject(`/galene-api/v0/.groups/${group}/.tokens/${token}`,
|
return await getObject(`/skald-api/v0/.groups/${group}/.tokens/${token}`,
|
||||||
etag);
|
etag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +353,7 @@ async function createToken(group, template) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let r = await fetch(
|
let r = await fetch(
|
||||||
`/galene-api/v0/.groups/${group}/.tokens/`,
|
`/skald-api/v0/.groups/${group}/.tokens/`,
|
||||||
options);
|
options);
|
||||||
if(!r.ok)
|
if(!r.ok)
|
||||||
throw httpError(r);
|
throw httpError(r);
|
||||||
@@ -373,6 +373,6 @@ async function updateToken(group, token, etag) {
|
|||||||
if(!token.token)
|
if(!token.token)
|
||||||
throw new Error("Unnamed token");
|
throw new Error("Unnamed token");
|
||||||
return await updateObject(
|
return await updateObject(
|
||||||
`/galene-api/v0/.groups/${group}/.tokens/${token.token}`,
|
`/skald-api/v0/.groups/${group}/.tokens/${token.token}`,
|
||||||
token, etag);
|
token, etag);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1619,7 +1619,7 @@ function TransferredFile(sc, userid, id, up, username, name, mimetype, size) {
|
|||||||
* The negotiated file-transfer protocol version.
|
* The negotiated file-transfer protocol version.
|
||||||
*
|
*
|
||||||
* This is the version of the file-transfer protocol, and is not
|
* This is the version of the file-transfer protocol, and is not
|
||||||
* necessarily equal to the version of the Galene protocol used by the
|
* necessarily equal to the version of the Skald protocol used by the
|
||||||
* server connection.
|
* server connection.
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
|
|||||||
@@ -1109,7 +1109,7 @@ legend {
|
|||||||
border-right: 1px solid #dcdcdc;
|
border-right: 1px solid #dcdcdc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#left-sidebar .galene-header {
|
#left-sidebar .skald-header {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1127,7 +1127,7 @@ header .collapse:hover {
|
|||||||
color: #c2a4e0;
|
color: #c2a4e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.galene-header {
|
.skald-header {
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
color: #dbd9d9;
|
color: #dbd9d9;
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Galène</title>
|
<title>Skald</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta http-equiv="ScreenOrientation" content="autoRotate:disabled">
|
<meta http-equiv="ScreenOrientation" content="autoRotate:disabled">
|
||||||
<link rel="stylesheet" type="text/css" href="/common.css"/>
|
<link rel="stylesheet" type="text/css" href="/common.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/galene.css"/>
|
<link rel="stylesheet" type="text/css" href="/skald.css"/>
|
||||||
<link rel="author" href="https://www.irif.fr/~jch/"/>
|
<link rel="author" href="https://www.irif.fr/~jch/"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/third-party/fontawesome/css/fontawesome.min.css"/>
|
<link rel="stylesheet" type="text/css" href="/third-party/fontawesome/css/fontawesome.min.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/third-party/fontawesome/css/solid.min.css"/>
|
<link rel="stylesheet" type="text/css" href="/third-party/fontawesome/css/solid.min.css"/>
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
<div class="row full-height">
|
<div class="row full-height">
|
||||||
<nav id="left-sidebar">
|
<nav id="left-sidebar">
|
||||||
<div class="users-header">
|
<div class="users-header">
|
||||||
<div class="galene-header">Galène</div>
|
<div class="skald-header">Skald</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-sep"></div>
|
<div class="header-sep"></div>
|
||||||
<div id="users"></div>
|
<div id="users"></div>
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
<button class="collapse" aria-label="Toggle left panel" aria-expanded="true" id="sidebarCollapse">
|
<button class="collapse" aria-label="Toggle left panel" aria-expanded="true" id="sidebarCollapse">
|
||||||
<i class="fas fa-align-left" aria-hidden="true"></i>
|
<i class="fas fa-align-left" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<h1 id="title" class="header-title">Galène</h1>
|
<h1 id="title" class="header-title">Skald</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="nav-menu">
|
<ul class="nav-menu">
|
||||||
@@ -312,6 +312,6 @@
|
|||||||
<script src="/protocol.js" defer></script>
|
<script src="/protocol.js" defer></script>
|
||||||
<script src="/third-party/toastify/toastify.js" defer></script>
|
<script src="/third-party/toastify/toastify.js" defer></script>
|
||||||
<script src="/third-party/contextual/contextual.js" defer></script>
|
<script src="/third-party/contextual/contextual.js" defer></script>
|
||||||
<script src="/galene.js" defer></script>
|
<script src="/skald.js" defer></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -2869,7 +2869,7 @@ function setTitle(title) {
|
|||||||
if(title)
|
if(title)
|
||||||
set(title);
|
set(title);
|
||||||
else
|
else
|
||||||
set('Galène');
|
set('Skald');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3245,7 +3245,7 @@ function gotUserMessage(id, dest, username, time, privileged, kind, error, messa
|
|||||||
if('share' in navigator) {
|
if('share' in navigator) {
|
||||||
try {
|
try {
|
||||||
navigator.share({
|
navigator.share({
|
||||||
title: `Invitation to Galene group ${message.group}`,
|
title: `Invitation to Skald group ${message.group}`,
|
||||||
text: f[0],
|
text: f[0],
|
||||||
url: f[1],
|
url: f[1],
|
||||||
});
|
});
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Galène statistics</title>
|
<title>Skald statistics</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="/common.css">
|
<link rel="stylesheet" href="/common.css">
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h1 id="title" class="navbar-brand">Galène statistics</h1>
|
<h1 id="title" class="navbar-brand">Skald statistics</h1>
|
||||||
<table id="stats-table"></table>
|
<table id="stats-table"></table>
|
||||||
<script src="/stats.js" defer></script>
|
<script src="/stats.js" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ async function listStats() {
|
|||||||
|
|
||||||
let l;
|
let l;
|
||||||
try {
|
try {
|
||||||
let r = await fetch('/galene-api/v0/.stats');
|
let r = await fetch('/skald-api/v0/.stats');
|
||||||
if(!r.ok)
|
if(!r.ok)
|
||||||
throw new Error(`${r.status} ${r.statusText}`);
|
throw new Error(`${r.status} ${r.statusText}`);
|
||||||
l = await r.json();
|
l = await r.json();
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"protocol.js",
|
"protocol.js",
|
||||||
"galene.js",
|
"skald.js",
|
||||||
"management.js",
|
"management.js",
|
||||||
"example/example.js"
|
"example/example.js"
|
||||||
]
|
]
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jech/galene/group"
|
"git.stormux.org/storm/skald/group"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GroupStats struct {
|
type GroupStats struct {
|
||||||
|
|||||||
@@ -26,12 +26,12 @@
|
|||||||
# PHASE 0: BASELINE INVENTORY AND GUARDRAILS
|
# PHASE 0: BASELINE INVENTORY AND GUARDRAILS
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
- Record the current upstream/fork point in CHANGES or a new fork note
|
X Record the current upstream/fork point in CHANGES or a new fork note
|
||||||
- Capture current baseline: `go test ./...` result before behavior changes
|
X Capture current baseline: `go test ./...` result before behavior changes
|
||||||
- Capture current baseline: `go build ./...` result before behavior changes
|
X Capture current baseline: `go build ./...` result before behavior changes
|
||||||
- Inventory generated/static assets, including static/example and third-party assets
|
- Inventory generated/static assets, including static/example and third-party assets
|
||||||
- Inventory all public URLs: /group/, /public-groups.json, /recordings/, /galene-api/
|
- Inventory all public URLs: /group/, /public-groups.json, /recordings/, /galene-api/
|
||||||
- Inventory all config/data paths: groups/, data/, recordings/, galenectl.json
|
- Inventory all config/data paths: groups/, data/, recordings/, skaldctl.json
|
||||||
- Inventory all Galene binary/service names in docs, scripts, examples, and tests
|
- Inventory all Galene binary/service names in docs, scripts, examples, and tests
|
||||||
- Decide whether existing stored data will be migrated manually or treated as incompatible
|
- Decide whether existing stored data will be migrated manually or treated as incompatible
|
||||||
- Keep the old LICENSE intact and preserve required attribution
|
- Keep the old LICENSE intact and preserve required attribution
|
||||||
@@ -40,23 +40,23 @@
|
|||||||
# PHASE 1: FOUNDATION AND TOTAL REBRANDING
|
# PHASE 1: FOUNDATION AND TOTAL REBRANDING
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
- Rename Go module: github.com/jech/galene -> git.stormux.org/storm/skald
|
X Rename Go module: github.com/jech/galene -> git.stormux.org/storm/skald
|
||||||
- Update all internal Go import paths across source and tests
|
X Update all internal Go import paths across source and tests
|
||||||
- Rename galene.go -> skald.go and keep the main package entrypoint working
|
X Rename galene.go -> skald.go and keep the main package entrypoint working
|
||||||
- Rename galenectl/ directory and binary to skaldctl/
|
X Rename galenectl/ directory and binary to skaldctl/
|
||||||
- Rename static/galene.css -> static/skald.css
|
X Rename static/galene.css -> static/skald.css
|
||||||
- Rename static/galene.js -> static/skald.js
|
X Rename static/galene.js -> static/skald.js
|
||||||
- Rename static/galene.html -> static/skald.html
|
X Rename static/galene.html -> static/skald.html
|
||||||
- Update webserver static serving to load skald.html and renamed assets
|
X Update webserver static serving to load skald.html and renamed assets
|
||||||
- Update all HTML, JS, CSS, docs, tests, and examples that reference renamed assets
|
X Update all HTML, JS, CSS, docs, tests, and examples that reference renamed assets
|
||||||
- Rename galene-*.md docs to skald-*.md
|
X Rename galene-*.md docs to skald-*.md
|
||||||
- Replace "Galene", "Galène", and "galene" with "Skald" and "skald" where they refer to this project
|
X Replace "Galene", "Galène", and "galene" with "Skald" and "skald" where they refer to this project
|
||||||
- Keep historical upstream references only where they are attribution, changelog history, or license context
|
X Keep historical upstream references only where they are attribution, changelog history, or license context
|
||||||
- Rename default binary, service, and install examples from galene to skald
|
X Rename default binary, service, and install examples from galene to skald
|
||||||
- Rename galenectl config file to skaldctl.json
|
X Rename galenectl config file to skaldctl.json
|
||||||
- Update CHANGES with Skald fork point and first Skald development section
|
X Update CHANGES with Skald fork point and first Skald development section
|
||||||
- Verify `go test ./...` compiles after the pure project rename pass
|
X Verify `go test ./...` compiles after the pure project rename pass
|
||||||
- Search for remaining Galene names and classify each survivor as attribution/history or a bug
|
X Search for remaining Galene names and classify each survivor as attribution/history or a bug
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# PHASE 2: HALL TERMINOLOGY AND DATA MODEL
|
# PHASE 2: HALL TERMINOLOGY AND DATA MODEL
|
||||||
@@ -92,13 +92,13 @@
|
|||||||
- Update static/protocol.js public API: ServerConnection.join and related callbacks
|
- Update static/protocol.js public API: ServerConnection.join and related callbacks
|
||||||
- Update static/management.js to use /skald-api/v0/.halls/
|
- Update static/management.js to use /skald-api/v0/.halls/
|
||||||
- Update static/mainpage.js to open /hall/ URLs and fetch /public-halls.json
|
- Update static/mainpage.js to open /hall/ URLs and fetch /public-halls.json
|
||||||
- Update stats endpoint naming only if it exposes Galene/group terminology
|
- Update stats endpoint naming only if it exposes Skald/group terminology
|
||||||
- Update skaldctl command names: create-hall, update-hall, delete-hall, list-halls
|
- Update skaldctl command names: create-hall, update-hall, delete-hall, list-halls
|
||||||
- Update skaldctl flags: -hall, -include-subhalls, -auto-subhalls, etc.
|
- Update skaldctl flags: -hall, -include-subhalls, -auto-subhalls, etc.
|
||||||
- Update skaldctl help text and error messages
|
- Update skaldctl help text and error messages
|
||||||
- Update API and webserver tests for /hall/ and /skald-api/
|
- Update API and webserver tests for /hall/ and /skald-api/
|
||||||
- Verify old /group/, /public-groups.json, /galene-api/, and .groups paths fail clearly
|
- Verify old /group/, /public-groups.json, /galene-api/, and .groups paths fail clearly
|
||||||
- Verify protocol backward compatibility with Galene is intentionally broken
|
- Verify protocol backward compatibility with Skald is intentionally broken
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# PHASE 4: BACKEND - STRIP VIDEO COMPLETELY
|
# PHASE 4: BACKEND - STRIP VIDEO COMPLETELY
|
||||||
@@ -189,7 +189,7 @@
|
|||||||
- Update TURN/STUN docs only where project name or URLs changed
|
- Update TURN/STUN docs only where project name or URLs changed
|
||||||
- Update Docker/container or packaging files if present later
|
- Update Docker/container or packaging files if present later
|
||||||
- Update .gitignore for renamed binaries, config files, and generated artifacts
|
- Update .gitignore for renamed binaries, config files, and generated artifacts
|
||||||
- Verify there are no stale install commands that build or run galene/galenectl
|
- Verify there are no stale install commands that build or run skald/skaldctl
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# PHASE 8: DOCUMENTATION
|
# PHASE 8: DOCUMENTATION
|
||||||
@@ -204,7 +204,7 @@
|
|||||||
- Remove video, camera, screenshare, simulcast, SVC, and WebM recording instructions
|
- Remove video, camera, screenshare, simulcast, SVC, and WebM recording instructions
|
||||||
- Add Ogg Opus recording documentation
|
- Add Ogg Opus recording documentation
|
||||||
- Document that incoming video is rejected by design
|
- Document that incoming video is rejected by design
|
||||||
- Document that Galene protocol/API compatibility is intentionally broken
|
- Document that Skald protocol/API compatibility is intentionally broken
|
||||||
- Document any required external ffmpeg dependency if the recorder uses ffmpeg
|
- Document any required external ffmpeg dependency if the recorder uses ffmpeg
|
||||||
- Check docs for old real-person sample usernames and replace with placeholders
|
- Check docs for old real-person sample usernames and replace with placeholders
|
||||||
|
|
||||||
@@ -235,4 +235,4 @@
|
|||||||
- Test: play the recording in a standard audio player
|
- Test: play the recording in a standard audio player
|
||||||
- Test: restart server and verify halls/config load from the new paths
|
- Test: restart server and verify halls/config load from the new paths
|
||||||
- Remove obsolete files that are no longer served or built
|
- Remove obsolete files that are no longer served or built
|
||||||
- Do a final diff review for accidental compatibility shims or stale Galene naming
|
- Do a final diff review for accidental compatibility shims or stale Skald naming
|
||||||
|
|||||||
+64
-12
@@ -6,6 +6,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestJWKHS256(t *testing.T) {
|
func TestJWKHS256(t *testing.T) {
|
||||||
@@ -113,6 +115,17 @@ func TestMatchGroup(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeTestJWT(t *testing.T, key any, claims jwt.MapClaims) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
value, err := token.SignedString(key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SignedString: %v", err)
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
func TestJWT(t *testing.T) {
|
func TestJWT(t *testing.T) {
|
||||||
key := `{"alg":"HS256","k":"H7pCkktUl5KyPCZ7CKw09y1j460tfIv4dRcS1XstUKY","key_ops":["sign","verify"],"kty":"oct"}`
|
key := `{"alg":"HS256","k":"H7pCkktUl5KyPCZ7CKw09y1j460tfIv4dRcS1XstUKY","key_ops":["sign","verify"],"kty":"oct"}`
|
||||||
var k map[string]interface{}
|
var k map[string]interface{}
|
||||||
@@ -122,17 +135,35 @@ func TestJWT(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
keys := []map[string]interface{}{k}
|
keys := []map[string]interface{}{k}
|
||||||
|
signingKey, err := ParseKey(k)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ParseKey: %v", err)
|
||||||
|
}
|
||||||
john := "john"
|
john := "john"
|
||||||
jack := "jack"
|
jack := "jack"
|
||||||
|
baseClaims := jwt.MapClaims{
|
||||||
|
"aud": "https://skald.org:8443/group/auth/",
|
||||||
|
"permissions": []string{"present"},
|
||||||
|
"iat": int64(1645310294),
|
||||||
|
"exp": int64(2906750294),
|
||||||
|
"iss": "http://localhost:1234/",
|
||||||
|
}
|
||||||
|
|
||||||
goodToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDI5NCwiZXhwIjoyOTA2NzUwMjk0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0.6xXpgBkBMn4PSBpnwYHb-gRn_Q97Yq9DoKkAf2_6iwc"
|
goodToken := makeTestJWT(t, signingKey, jwt.MapClaims{
|
||||||
|
"sub": "john",
|
||||||
|
"aud": baseClaims["aud"],
|
||||||
|
"permissions": baseClaims["permissions"],
|
||||||
|
"iat": baseClaims["iat"],
|
||||||
|
"exp": baseClaims["exp"],
|
||||||
|
"iss": baseClaims["iss"],
|
||||||
|
})
|
||||||
|
|
||||||
tok, err := Parse(goodToken, keys)
|
tok, err := Parse(goodToken, keys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Couldn't parse goodToken: %v", err)
|
t.Errorf("Couldn't parse goodToken: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
username, perms, err := tok.Check("galene.org:8443", "auth", &john)
|
username, perms, err := tok.Check("skald.org:8443", "auth", &john)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("goodToken is not valid: %v", err)
|
t.Errorf("goodToken is not valid: %v", err)
|
||||||
}
|
}
|
||||||
@@ -140,7 +171,7 @@ func TestJWT(t *testing.T) {
|
|||||||
t.Errorf("Expected john, [present], got %v %v", username, perms)
|
t.Errorf("Expected john, [present], got %v %v", username, perms)
|
||||||
}
|
}
|
||||||
|
|
||||||
username, perms, err = tok.Check("galene.org:8443", "auth", &jack)
|
username, perms, err = tok.Check("skald.org:8443", "auth", &jack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("goodToken is not valid: %v", err)
|
t.Errorf("goodToken is not valid: %v", err)
|
||||||
}
|
}
|
||||||
@@ -153,28 +184,35 @@ func TestJWT(t *testing.T) {
|
|||||||
t.Errorf("goodToken is not valid: %v", err)
|
t.Errorf("goodToken is not valid: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = tok.Check("galene.org", "auth", &john)
|
_, _, err = tok.Check("skald.org", "auth", &john)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("goodToken is valid for wrong hostname")
|
t.Errorf("goodToken is valid for wrong hostname")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = tok.Check("galene.org:8443", "not-auth", &john)
|
_, _, err = tok.Check("skald.org:8443", "not-auth", &john)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("goodToken is valid for wrong group")
|
t.Errorf("goodToken is valid for wrong group")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = tok.Check("galene.org:8443", "auth/subgroup", &john)
|
_, _, err = tok.Check("skald.org:8443", "auth/subgroup", &john)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("goodToken is valid for subgroup")
|
t.Errorf("goodToken is valid for subgroup")
|
||||||
}
|
}
|
||||||
|
|
||||||
emptySubToken := "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIiLCJhdWQiOiJodHRwczovL2dhbGVuZS5vcmc6ODQ0My9ncm91cC9hdXRoLyIsInBlcm1pc3Npb25zIjpbInByZXNlbnQiXSwiaWF0IjoxNjQ1MzEwMjk0LCJleHAiOjI5MDY3NTAyOTQsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MTIzNC8ifQo.xwpHIRzKAIgiHKG1pVQyZlXcolmvRwNvBm6FN2gTwZw"
|
emptySubToken := makeTestJWT(t, signingKey, jwt.MapClaims{
|
||||||
|
"sub": "",
|
||||||
|
"aud": baseClaims["aud"],
|
||||||
|
"permissions": baseClaims["permissions"],
|
||||||
|
"iat": baseClaims["iat"],
|
||||||
|
"exp": baseClaims["exp"],
|
||||||
|
"iss": baseClaims["iss"],
|
||||||
|
})
|
||||||
|
|
||||||
tok, err = Parse(emptySubToken, keys)
|
tok, err = Parse(emptySubToken, keys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Couldn't parse emptySubToken: %v", err)
|
t.Errorf("Couldn't parse emptySubToken: %v", err)
|
||||||
}
|
}
|
||||||
username, perms, err = tok.Check("galene.org:8443", "auth", &jack)
|
username, perms, err = tok.Check("skald.org:8443", "auth", &jack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("anonymousToken is not valid: %v", err)
|
t.Errorf("anonymousToken is not valid: %v", err)
|
||||||
}
|
}
|
||||||
@@ -182,13 +220,19 @@ func TestJWT(t *testing.T) {
|
|||||||
t.Errorf("Expected \"\", [present], got %v %v", username, perms)
|
t.Errorf("Expected \"\", [present], got %v %v", username, perms)
|
||||||
}
|
}
|
||||||
|
|
||||||
noSubToken := "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJodHRwczovL2dhbGVuZS5vcmc6ODQ0My9ncm91cC9hdXRoLyIsInBlcm1pc3Npb25zIjpbInByZXNlbnQiXSwiaWF0IjoxNjQ1MzEwMjk0LCJleHAiOjI5MDY3NTAyOTQsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MTIzNC8ifQo.7LvoZEKPNVvsRe8SjLxmKa1TgjTA4ZQo2LMPJSXl-ro"
|
noSubToken := makeTestJWT(t, signingKey, jwt.MapClaims{
|
||||||
|
"aud": baseClaims["aud"],
|
||||||
|
"permissions": baseClaims["permissions"],
|
||||||
|
"iat": baseClaims["iat"],
|
||||||
|
"exp": baseClaims["exp"],
|
||||||
|
"iss": baseClaims["iss"],
|
||||||
|
})
|
||||||
|
|
||||||
tok, err = Parse(noSubToken, keys)
|
tok, err = Parse(noSubToken, keys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Couldn't parse noSubToken: %v", err)
|
t.Errorf("Couldn't parse noSubToken: %v", err)
|
||||||
}
|
}
|
||||||
username, perms, err = tok.Check("galene.org:8443", "auth", &jack)
|
username, perms, err = tok.Check("skald.org:8443", "auth", &jack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("noSubToken is not valid: %v", err)
|
t.Errorf("noSubToken is not valid: %v", err)
|
||||||
}
|
}
|
||||||
@@ -216,13 +260,21 @@ func TestJWT(t *testing.T) {
|
|||||||
t.Errorf("noneToken is good")
|
t.Errorf("noneToken is good")
|
||||||
}
|
}
|
||||||
|
|
||||||
subgroupsToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJpbmNsdWRlLXN1Ymdyb3VwcyI6dHJ1ZSwicGVybWlzc2lvbnMiOlsicHJlc2VudCJdLCJpYXQiOjE2NDUzMTAyOTQsImV4cCI6MjkwNjc1MDI5NCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDoxMjM0LyJ9.ty4B7cJPCGJPMadwOCNMGQirIByj1L9AxWiDFnBm5wA"
|
subgroupsToken := makeTestJWT(t, signingKey, jwt.MapClaims{
|
||||||
|
"sub": "john",
|
||||||
|
"aud": baseClaims["aud"],
|
||||||
|
"include-subgroups": true,
|
||||||
|
"permissions": baseClaims["permissions"],
|
||||||
|
"iat": baseClaims["iat"],
|
||||||
|
"exp": baseClaims["exp"],
|
||||||
|
"iss": baseClaims["iss"],
|
||||||
|
})
|
||||||
tok, err = Parse(subgroupsToken, keys)
|
tok, err = Parse(subgroupsToken, keys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("subgroupsToken is not valid: %v", err)
|
t.Errorf("subgroupsToken is not valid: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = tok.Check("galene.org:8443", "auth/subgroup", &john)
|
_, _, err = tok.Check("skald.org:8443", "auth/subgroup", &john)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("subgroupsToken is not valid for subgroup: %v", err)
|
t.Errorf("subgroupsToken is not valid for subgroup: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -184,7 +184,7 @@ func (state *state) load() (string, error) {
|
|||||||
state.reset()
|
state.reset()
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
// the "message" permission was introduced in Galene 0.9,
|
// the "message" permission was introduced in Skald 0.9,
|
||||||
// so add it to tokens read from disk. We can remove this
|
// so add it to tokens read from disk. We can remove this
|
||||||
// hack in late 2024.
|
// hack in late 2024.
|
||||||
if !member("message", t.Permissions) {
|
if !member("message", t.Permissions) {
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ func TestToken(t *testing.T) {
|
|||||||
t.Fatalf("Parse: %v", err)
|
t.Fatalf("Parse: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = token.Check("galene.org:8443", "group", &user)
|
_, _, err = token.Check("skald.org:8443", "group", &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Check: %v", err)
|
t.Errorf("Check: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ func Start() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
username = "galene"
|
username = "skald"
|
||||||
buf := make([]byte, 6)
|
buf := make([]byte, 6)
|
||||||
_, err = rand.Read(buf)
|
_, err = rand.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -187,9 +187,9 @@ func Start() error {
|
|||||||
log.Printf("Starting built-in TURN server on %v", addr.String())
|
log.Printf("Starting built-in TURN server on %v", addr.String())
|
||||||
|
|
||||||
server.server, err = turn.NewServer(turn.ServerConfig{
|
server.server, err = turn.NewServer(turn.ServerConfig{
|
||||||
Realm: "galene.org",
|
Realm: "skald.org",
|
||||||
AuthHandler: func(u, r string, src net.Addr) ([]byte, bool) {
|
AuthHandler: func(u, r string, src net.Addr) ([]byte, bool) {
|
||||||
if u != username || r != "galene.org" {
|
if u != username || r != "skald.org" {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
return turn.GenerateAuthKey(u, r, password), true
|
return turn.GenerateAuthKey(u, r, password), true
|
||||||
|
|||||||
+7
-7
@@ -13,9 +13,9 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
"github.com/jech/galene/group"
|
"git.stormux.org/storm/skald/group"
|
||||||
"github.com/jech/galene/stats"
|
"git.stormux.org/storm/skald/stats"
|
||||||
"github.com/jech/galene/token"
|
"git.stormux.org/storm/skald/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
// checkAdmin checks whether the client authentifies as an administrator
|
// checkAdmin checks whether the client authentifies as an administrator
|
||||||
@@ -25,7 +25,7 @@ func checkAdmin(w http.ResponseWriter, r *http.Request) bool {
|
|||||||
ok, _ = adminMatch(username, password)
|
ok, _ = adminMatch(username, password)
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
failAuthentication(w, "/galene-api/")
|
failAuthentication(w, "/skald-api/")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -71,7 +71,7 @@ func checkPasswordAdmin(w http.ResponseWriter, r *http.Request, groupname, user
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
failAuthentication(w, "/galene-api/")
|
failAuthentication(w, "/skald-api/")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,12 +141,12 @@ func apiCORS(w http.ResponseWriter, r *http.Request, methods string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func apiHandler(w http.ResponseWriter, r *http.Request) {
|
func apiHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if !strings.HasPrefix(r.URL.Path, "/galene-api/") {
|
if !strings.HasPrefix(r.URL.Path, "/skald-api/") {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
first, kind, rest := splitPath(r.URL.Path[len("/galene-api"):])
|
first, kind, rest := splitPath(r.URL.Path[len("/skald-api"):])
|
||||||
if first != "/v0" {
|
if first != "/v0" {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
|
|||||||
+52
-52
@@ -15,8 +15,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jech/galene/group"
|
"git.stormux.org/storm/skald/group"
|
||||||
"github.com/jech/galene/token"
|
"git.stormux.org/storm/skald/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
var setupOnce sync.Once
|
var setupOnce sync.Once
|
||||||
@@ -115,19 +115,19 @@ func TestApi(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var groups []string
|
var groups []string
|
||||||
err = getJSON("/galene-api/v0/.groups/", &groups)
|
err = getJSON("/skald-api/v0/.groups/", &groups)
|
||||||
if err != nil || len(groups) != 0 {
|
if err != nil || len(groups) != 0 {
|
||||||
t.Errorf("Get groups: %v", err)
|
t.Errorf("Get groups: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := do("PUT", "/galene-api/v0/.groups/test/",
|
resp, err := do("PUT", "/skald-api/v0/.groups/test/",
|
||||||
"application/json", "\"foo\"", "",
|
"application/json", "\"foo\"", "",
|
||||||
"{}")
|
"{}")
|
||||||
if err != nil || resp.StatusCode != http.StatusPreconditionFailed {
|
if err != nil || resp.StatusCode != http.StatusPreconditionFailed {
|
||||||
t.Errorf("Create group (bad ETag): %v %v", err, resp.StatusCode)
|
t.Errorf("Create group (bad ETag): %v %v", err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("PUT", "/galene-api/v0/.groups/test/",
|
resp, err = do("PUT", "/skald-api/v0/.groups/test/",
|
||||||
"text/plain", "", "",
|
"text/plain", "", "",
|
||||||
"Hello, world!")
|
"Hello, world!")
|
||||||
if err != nil || resp.StatusCode != http.StatusUnsupportedMediaType {
|
if err != nil || resp.StatusCode != http.StatusUnsupportedMediaType {
|
||||||
@@ -135,7 +135,7 @@ func TestApi(t *testing.T) {
|
|||||||
err, resp.StatusCode)
|
err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("PUT", "/galene-api/v0/.groups/test/",
|
resp, err = do("PUT", "/skald-api/v0/.groups/test/",
|
||||||
"application/json", "", "*",
|
"application/json", "", "*",
|
||||||
"{}")
|
"{}")
|
||||||
if err != nil || resp.StatusCode != http.StatusCreated {
|
if err != nil || resp.StatusCode != http.StatusCreated {
|
||||||
@@ -143,30 +143,30 @@ func TestApi(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var desc *group.Description
|
var desc *group.Description
|
||||||
err = getJSON("/galene-api/v0/.groups/test/", &desc)
|
err = getJSON("/skald-api/v0/.groups/test/", &desc)
|
||||||
if err != nil || len(desc.Users) != 0 {
|
if err != nil || len(desc.Users) != 0 {
|
||||||
t.Errorf("Get group: %v", err)
|
t.Errorf("Get group: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("PUT", "/galene-api/v0/.groups/test/",
|
resp, err = do("PUT", "/skald-api/v0/.groups/test/",
|
||||||
"application/json", "", "*",
|
"application/json", "", "*",
|
||||||
"{}")
|
"{}")
|
||||||
if err != nil || resp.StatusCode != http.StatusPreconditionFailed {
|
if err != nil || resp.StatusCode != http.StatusPreconditionFailed {
|
||||||
t.Errorf("Create group (bad ETag): %v %v", err, resp.StatusCode)
|
t.Errorf("Create group (bad ETag): %v %v", err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("DELETE", "/galene-api/v0/.groups/test/",
|
resp, err = do("DELETE", "/skald-api/v0/.groups/test/",
|
||||||
"", "", "*", "")
|
"", "", "*", "")
|
||||||
if err != nil || resp.StatusCode != http.StatusPreconditionFailed {
|
if err != nil || resp.StatusCode != http.StatusPreconditionFailed {
|
||||||
t.Errorf("Delete group (bad ETag): %v %v", err, resp.StatusCode)
|
t.Errorf("Delete group (bad ETag): %v %v", err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = getJSON("/galene-api/v0/.groups/", &groups)
|
err = getJSON("/skald-api/v0/.groups/", &groups)
|
||||||
if err != nil || len(groups) != 1 || groups[0] != "test" {
|
if err != nil || len(groups) != 1 || groups[0] != "test" {
|
||||||
t.Errorf("Get groups: %v %v", err, groups)
|
t.Errorf("Get groups: %v %v", err, groups)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("PUT", "/galene-api/v0/.groups/test/.keys",
|
resp, err = do("PUT", "/skald-api/v0/.groups/test/.keys",
|
||||||
"application/jwk-set+json", "", "",
|
"application/jwk-set+json", "", "",
|
||||||
`{"keys": [{
|
`{"keys": [{
|
||||||
"kty": "oct", "alg": "HS256",
|
"kty": "oct", "alg": "HS256",
|
||||||
@@ -176,12 +176,12 @@ func TestApi(t *testing.T) {
|
|||||||
t.Errorf("Set key: %v %v", err, resp.StatusCode)
|
t.Errorf("Set key: %v %v", err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = getJSON("/galene-api/v0/.groups/test/.users/", &groups)
|
err = getJSON("/skald-api/v0/.groups/test/.users/", &groups)
|
||||||
if err != nil || len(groups) != 0 {
|
if err != nil || len(groups) != 0 {
|
||||||
t.Errorf("Get users: %v", err)
|
t.Errorf("Get users: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("PUT", "/galene-api/v0/.groups/test/.users/jch",
|
resp, err = do("PUT", "/skald-api/v0/.groups/test/.users/jch",
|
||||||
"text/plain", "", "*",
|
"text/plain", "", "*",
|
||||||
`hello, world!`)
|
`hello, world!`)
|
||||||
if err != nil || resp.StatusCode != http.StatusUnsupportedMediaType {
|
if err != nil || resp.StatusCode != http.StatusUnsupportedMediaType {
|
||||||
@@ -189,7 +189,7 @@ func TestApi(t *testing.T) {
|
|||||||
err, resp.StatusCode)
|
err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("PUT", "/galene-api/v0/.groups/test/.users/jch",
|
resp, err = do("PUT", "/skald-api/v0/.groups/test/.users/jch",
|
||||||
"application/json", "", "*",
|
"application/json", "", "*",
|
||||||
`{"permissions": "present"}`)
|
`{"permissions": "present"}`)
|
||||||
if err != nil || resp.StatusCode != http.StatusCreated {
|
if err != nil || resp.StatusCode != http.StatusCreated {
|
||||||
@@ -197,26 +197,26 @@ func TestApi(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var users []string
|
var users []string
|
||||||
err = getJSON("/galene-api/v0/.groups/test/.users/", &users)
|
err = getJSON("/skald-api/v0/.groups/test/.users/", &users)
|
||||||
if err != nil || len(users) != 1 || users[0] != "jch" {
|
if err != nil || len(users) != 1 || users[0] != "jch" {
|
||||||
t.Errorf("Get users: %v %v", err, users)
|
t.Errorf("Get users: %v %v", err, users)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("PUT", "/galene-api/v0/.groups/test/.users/jch",
|
resp, err = do("PUT", "/skald-api/v0/.groups/test/.users/jch",
|
||||||
"application/json", "", "*",
|
"application/json", "", "*",
|
||||||
`{"permissions": "present"}`)
|
`{"permissions": "present"}`)
|
||||||
if err != nil || resp.StatusCode != http.StatusPreconditionFailed {
|
if err != nil || resp.StatusCode != http.StatusPreconditionFailed {
|
||||||
t.Errorf("Create user (bad ETag): %v %v", err, resp.StatusCode)
|
t.Errorf("Create user (bad ETag): %v %v", err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("PUT", "/galene-api/v0/.groups/test/.users/jch/.password",
|
resp, err = do("PUT", "/skald-api/v0/.groups/test/.users/jch/.password",
|
||||||
"application/json", "", "",
|
"application/json", "", "",
|
||||||
`"toto"`)
|
`"toto"`)
|
||||||
if err != nil || resp.StatusCode != http.StatusNoContent {
|
if err != nil || resp.StatusCode != http.StatusNoContent {
|
||||||
t.Errorf("Set password (PUT): %v %v", err, resp.StatusCode)
|
t.Errorf("Set password (PUT): %v %v", err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("POST", "/galene-api/v0/.groups/test/.users/jch/.password",
|
resp, err = do("POST", "/skald-api/v0/.groups/test/.users/jch/.password",
|
||||||
"text/plain", "", "",
|
"text/plain", "", "",
|
||||||
`toto`)
|
`toto`)
|
||||||
if err != nil || resp.StatusCode != http.StatusNoContent {
|
if err != nil || resp.StatusCode != http.StatusNoContent {
|
||||||
@@ -224,7 +224,7 @@ func TestApi(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var user group.UserDescription
|
var user group.UserDescription
|
||||||
err = getJSON("/galene-api/v0/.groups/test/.users/jch", &user)
|
err = getJSON("/skald-api/v0/.groups/test/.users/jch", &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Get user: %v", err)
|
t.Errorf("Get user: %v", err)
|
||||||
}
|
}
|
||||||
@@ -245,7 +245,7 @@ func TestApi(t *testing.T) {
|
|||||||
t.Errorf("Password.Type: %v", desc.Users["jch"].Password.Type)
|
t.Errorf("Password.Type: %v", desc.Users["jch"].Password.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("DELETE", "/galene-api/v0/.groups/test/.users/jch",
|
resp, err = do("DELETE", "/skald-api/v0/.groups/test/.users/jch",
|
||||||
"", "", "", "")
|
"", "", "", "")
|
||||||
if err != nil || resp.StatusCode != http.StatusNoContent {
|
if err != nil || resp.StatusCode != http.StatusNoContent {
|
||||||
t.Errorf("Delete group: %v %v", err, resp.StatusCode)
|
t.Errorf("Delete group: %v %v", err, resp.StatusCode)
|
||||||
@@ -260,14 +260,14 @@ func TestApi(t *testing.T) {
|
|||||||
t.Errorf("Users (after delete): %#v", desc.Users)
|
t.Errorf("Users (after delete): %#v", desc.Users)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("PUT", "/galene-api/v0/.groups/test/.wildcard-user",
|
resp, err = do("PUT", "/skald-api/v0/.groups/test/.wildcard-user",
|
||||||
"application/json", "", "*",
|
"application/json", "", "*",
|
||||||
`{"permissions": "present"}`)
|
`{"permissions": "present"}`)
|
||||||
if err != nil || resp.StatusCode != http.StatusCreated {
|
if err != nil || resp.StatusCode != http.StatusCreated {
|
||||||
t.Errorf("Create wildcard user: %v %v", err, resp.StatusCode)
|
t.Errorf("Create wildcard user: %v %v", err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = getJSON("/galene-api/v0/.groups/test/.wildcard-user", &user)
|
err = getJSON("/skald-api/v0/.groups/test/.wildcard-user", &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Get wildcard user: %v", err)
|
t.Errorf("Get wildcard user: %v", err)
|
||||||
}
|
}
|
||||||
@@ -281,7 +281,7 @@ func TestApi(t *testing.T) {
|
|||||||
t.Errorf("Got %v, expected %v", desc.WildcardUser, user)
|
t.Errorf("Got %v, expected %v", desc.WildcardUser, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("DELETE", "/galene-api/v0/.groups/test/.wildcard-user",
|
resp, err = do("DELETE", "/skald-api/v0/.groups/test/.wildcard-user",
|
||||||
"", "", "", "")
|
"", "", "", "")
|
||||||
if err != nil || resp.StatusCode != http.StatusNoContent {
|
if err != nil || resp.StatusCode != http.StatusNoContent {
|
||||||
t.Errorf("Delete wildcard user: %v %v", err, resp.StatusCode)
|
t.Errorf("Delete wildcard user: %v %v", err, resp.StatusCode)
|
||||||
@@ -300,33 +300,33 @@ func TestApi(t *testing.T) {
|
|||||||
t.Errorf("Keys: %v", len(desc.AuthKeys))
|
t.Errorf("Keys: %v", len(desc.AuthKeys))
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("POST", "/galene-api/v0/.groups/test/.tokens/",
|
resp, err = do("POST", "/skald-api/v0/.groups/test/.tokens/",
|
||||||
"application/json", "", "", `{"group":"bad"}`)
|
"application/json", "", "", `{"group":"bad"}`)
|
||||||
if err != nil || resp.StatusCode != http.StatusBadRequest {
|
if err != nil || resp.StatusCode != http.StatusBadRequest {
|
||||||
t.Errorf("Create token (bad group): %v %v", err, resp.StatusCode)
|
t.Errorf("Create token (bad group): %v %v", err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("POST", "/galene-api/v0/.groups/test/.tokens/",
|
resp, err = do("POST", "/skald-api/v0/.groups/test/.tokens/",
|
||||||
"application/json", "", "", "{}")
|
"application/json", "", "", "{}")
|
||||||
if err != nil || resp.StatusCode != http.StatusCreated {
|
if err != nil || resp.StatusCode != http.StatusCreated {
|
||||||
t.Errorf("Create token: %v %v", err, resp.StatusCode)
|
t.Errorf("Create token: %v %v", err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("POST", "/galene-api/v0/.groups/.tokens/",
|
resp, err = do("POST", "/skald-api/v0/.groups/.tokens/",
|
||||||
"application/json", "", "", "{\"includeSubgroups\": true}")
|
"application/json", "", "", "{\"includeSubgroups\": true}")
|
||||||
if err != nil || resp.StatusCode != http.StatusCreated {
|
if err != nil || resp.StatusCode != http.StatusCreated {
|
||||||
t.Errorf("Create global token: %v %v", err, resp.StatusCode)
|
t.Errorf("Create global token: %v %v", err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
var toknames []string
|
var toknames []string
|
||||||
err = getJSON("/galene-api/v0/.groups/test/.tokens/", &toknames)
|
err = getJSON("/skald-api/v0/.groups/test/.tokens/", &toknames)
|
||||||
if err != nil || len(toknames) != 1 {
|
if err != nil || len(toknames) != 1 {
|
||||||
t.Errorf("Get tokens: %v %v", err, toknames)
|
t.Errorf("Get tokens: %v %v", err, toknames)
|
||||||
}
|
}
|
||||||
tokname := toknames[0]
|
tokname := toknames[0]
|
||||||
|
|
||||||
var globalToknames []string
|
var globalToknames []string
|
||||||
err = getJSON("/galene-api/v0/.groups/test/.tokens/", &globalToknames)
|
err = getJSON("/skald-api/v0/.groups/test/.tokens/", &globalToknames)
|
||||||
if err != nil || len(globalToknames) != 1 {
|
if err != nil || len(globalToknames) != 1 {
|
||||||
t.Errorf("Get global tokens: %v %v", err, globalToknames)
|
t.Errorf("Get global tokens: %v %v", err, globalToknames)
|
||||||
}
|
}
|
||||||
@@ -336,7 +336,7 @@ func TestApi(t *testing.T) {
|
|||||||
t.Errorf("token.List: %v %v", tokens, err)
|
t.Errorf("token.List: %v %v", tokens, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenpath := "/galene-api/v0/.groups/test/.tokens/" + tokname
|
tokenpath := "/skald-api/v0/.groups/test/.tokens/" + tokname
|
||||||
var tok token.Stateful
|
var tok token.Stateful
|
||||||
err = getJSON(tokenpath, &tok)
|
err = getJSON(tokenpath, &tok)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -375,13 +375,13 @@ func TestApi(t *testing.T) {
|
|||||||
t.Errorf("Got %v, expected %v (%v)", tok.Expires, e, err)
|
t.Errorf("Got %v, expected %v (%v)", tok.Expires, e, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("PUT", "/galene-api/v0/.groups/test2",
|
resp, err = do("PUT", "/skald-api/v0/.groups/test2",
|
||||||
"application/json", "", "*", "{}")
|
"application/json", "", "*", "{}")
|
||||||
if err != nil || resp.StatusCode != http.StatusCreated {
|
if err != nil || resp.StatusCode != http.StatusCreated {
|
||||||
t.Errorf("Create test2: %v %v", err, resp.StatusCode)
|
t.Errorf("Create test2: %v %v", err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenpath2 := "/galene-api/v0/.groups/test2/.tokens/" + tokname
|
tokenpath2 := "/skald-api/v0/.groups/test2/.tokens/" + tokname
|
||||||
resp, err = do("GET", tokenpath2, "", "", "", "")
|
resp, err = do("GET", tokenpath2, "", "", "", "")
|
||||||
if err != nil || resp.StatusCode != http.StatusNotFound {
|
if err != nil || resp.StatusCode != http.StatusNotFound {
|
||||||
t.Errorf("Get token in bad group: %v %v", err, resp.StatusCode)
|
t.Errorf("Get token in bad group: %v %v", err, resp.StatusCode)
|
||||||
@@ -402,13 +402,13 @@ func TestApi(t *testing.T) {
|
|||||||
t.Errorf("Token list: %v %v", tokens, err)
|
t.Errorf("Token list: %v %v", tokens, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("DELETE", "/galene-api/v0/.groups/test/.keys",
|
resp, err = do("DELETE", "/skald-api/v0/.groups/test/.keys",
|
||||||
"", "", "", "")
|
"", "", "", "")
|
||||||
if err != nil || resp.StatusCode != http.StatusNoContent {
|
if err != nil || resp.StatusCode != http.StatusNoContent {
|
||||||
t.Errorf("Delete keys: %v %v", err, resp.StatusCode)
|
t.Errorf("Delete keys: %v %v", err, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = do("DELETE", "/galene-api/v0/.groups/test/",
|
resp, err = do("DELETE", "/skald-api/v0/.groups/test/",
|
||||||
"", "", "", "")
|
"", "", "", "")
|
||||||
if err != nil || resp.StatusCode != http.StatusNoContent {
|
if err != nil || resp.StatusCode != http.StatusNoContent {
|
||||||
t.Errorf("Delete group: %v %v", err, resp.StatusCode)
|
t.Errorf("Delete group: %v %v", err, resp.StatusCode)
|
||||||
@@ -447,9 +447,9 @@ func TestApiBadAuth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do("GET", "/galene-api/v0/.stats")
|
do("GET", "/skald-api/v0/.stats")
|
||||||
do("GET", "/galene-api/v0/.groups/")
|
do("GET", "/skald-api/v0/.groups/")
|
||||||
do("PUT", "/galene-api/v0/.groups/test/")
|
do("PUT", "/skald-api/v0/.groups/test/")
|
||||||
|
|
||||||
f, err := os.Create(filepath.Join(group.Directory, "test.json"))
|
f, err := os.Create(filepath.Join(group.Directory, "test.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -460,20 +460,20 @@ func TestApiBadAuth(t *testing.T) {
|
|||||||
}\n`)
|
}\n`)
|
||||||
f.Close()
|
f.Close()
|
||||||
|
|
||||||
do("PUT", "/galene-api/v0/.groups/test/")
|
do("PUT", "/skald-api/v0/.groups/test/")
|
||||||
do("DELETE", "/galene-api/v0/.groups/test/")
|
do("DELETE", "/skald-api/v0/.groups/test/")
|
||||||
do("GET", "/galene-api/v0/.groups/test/.users/")
|
do("GET", "/skald-api/v0/.groups/test/.users/")
|
||||||
do("GET", "/galene-api/v0/.groups/test/.users/jch")
|
do("GET", "/skald-api/v0/.groups/test/.users/jch")
|
||||||
do("GET", "/galene-api/v0/.groups/test/.users/jch")
|
do("GET", "/skald-api/v0/.groups/test/.users/jch")
|
||||||
do("PUT", "/galene-api/v0/.groups/test/.users/jch")
|
do("PUT", "/skald-api/v0/.groups/test/.users/jch")
|
||||||
do("DELETE", "/galene-api/v0/.groups/test/.users/jch")
|
do("DELETE", "/skald-api/v0/.groups/test/.users/jch")
|
||||||
do("GET", "/galene-api/v0/.groups/test/.users/not-jch")
|
do("GET", "/skald-api/v0/.groups/test/.users/not-jch")
|
||||||
do("PUT", "/galene-api/v0/.groups/test/.users/not-jch")
|
do("PUT", "/skald-api/v0/.groups/test/.users/not-jch")
|
||||||
do("PUT", "/galene-api/v0/.groups/test/.users/jch/.password")
|
do("PUT", "/skald-api/v0/.groups/test/.users/jch/.password")
|
||||||
do("POST", "/galene-api/v0/.groups/test/.users/jch/.password")
|
do("POST", "/skald-api/v0/.groups/test/.users/jch/.password")
|
||||||
do("GET", "/galene-api/v0/.groups/test/.tokens/")
|
do("GET", "/skald-api/v0/.groups/test/.tokens/")
|
||||||
do("POST", "/galene-api/v0/.groups/test/.tokens/")
|
do("POST", "/skald-api/v0/.groups/test/.tokens/")
|
||||||
do("GET", "/galene-api/v0/.groups/test/.tokens/token")
|
do("GET", "/skald-api/v0/.groups/test/.tokens/token")
|
||||||
do("PUT", "/galene-api/v0/.groups/test/.tokens/token")
|
do("PUT", "/skald-api/v0/.groups/test/.tokens/token")
|
||||||
do("DELETE", "/galene-api/v0/.groups/test/.tokens/token")
|
do("DELETE", "/skald-api/v0/.groups/test/.tokens/token")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
|
||||||
|
"git.stormux.org/storm/skald/diskwriter"
|
||||||
|
"git.stormux.org/storm/skald/group"
|
||||||
|
"git.stormux.org/storm/skald/rtpconn"
|
||||||
"github.com/jech/cert"
|
"github.com/jech/cert"
|
||||||
"github.com/jech/galene/diskwriter"
|
|
||||||
"github.com/jech/galene/group"
|
|
||||||
"github.com/jech/galene/rtpconn"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var server *http.Server
|
var server *http.Server
|
||||||
@@ -44,7 +44,7 @@ func Serve(address string, dataDir string) error {
|
|||||||
http.HandleFunc("/recordings/", recordingsHandler)
|
http.HandleFunc("/recordings/", recordingsHandler)
|
||||||
http.HandleFunc("/ws", wsHandler)
|
http.HandleFunc("/ws", wsHandler)
|
||||||
http.HandleFunc("/public-groups.json", publicHandler)
|
http.HandleFunc("/public-groups.json", publicHandler)
|
||||||
http.HandleFunc("/galene-api/", apiHandler)
|
http.HandleFunc("/skald-api/", apiHandler)
|
||||||
|
|
||||||
s := &http.Server{
|
s := &http.Server{
|
||||||
Addr: address,
|
Addr: address,
|
||||||
@@ -371,7 +371,7 @@ func groupHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
status := g.Status(false, nil)
|
status := g.Status(false, nil)
|
||||||
cspHeader(w, status.AuthServer)
|
cspHeader(w, status.AuthServer)
|
||||||
serveFile(w, r, filepath.Join(StaticRoot, "galene.html"))
|
serveFile(w, r, filepath.Join(StaticRoot, "skald.html"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func baseURL(r *http.Request) (*url.URL, error) {
|
func baseURL(r *http.Request) (*url.URL, error) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
|
|
||||||
"github.com/jech/galene/group"
|
"git.stormux.org/storm/skald/group"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseGroupName(t *testing.T) {
|
func TestParseGroupName(t *testing.T) {
|
||||||
|
|||||||
+4
-4
@@ -17,10 +17,10 @@ import (
|
|||||||
|
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
|
|
||||||
"github.com/jech/galene/group"
|
"git.stormux.org/storm/skald/group"
|
||||||
"github.com/jech/galene/ice"
|
"git.stormux.org/storm/skald/ice"
|
||||||
"github.com/jech/galene/rtpconn"
|
"git.stormux.org/storm/skald/rtpconn"
|
||||||
"github.com/jech/galene/sdpfrag"
|
"git.stormux.org/storm/skald/sdpfrag"
|
||||||
)
|
)
|
||||||
|
|
||||||
var idSecret []byte
|
var idSecret []byte
|
||||||
|
|||||||
Reference in New Issue
Block a user