diff --git a/galene.go b/galene.go index a884c72..86745d0 100644 --- a/galene.go +++ b/galene.go @@ -149,7 +149,10 @@ func main() { for { select { case <-ticker.C: - go group.Update() + go func() { + group.Update() + token.Expire() + }() case <-slowTicker.C: go relayTest() case <-terminate: diff --git a/static/galene.js b/static/galene.js index c02726b..4e9197b 100644 --- a/static/galene.js +++ b/static/galene.js @@ -2130,7 +2130,7 @@ function userMenu(elt) { if(serverConnection.version !== "1" && serverConnection.permissions.indexOf('token') >= 0) { items.push({label: 'Invite user', onClick: () => { - serverConnection.groupAction('maketoken', units.d); + makeToken(null); }}); } if(serverConnection.permissions.indexOf('present') >= 0 && canFile()) @@ -3079,26 +3079,34 @@ function editTokenPredicate() { "You don't have permission to edit or list tokens" : null); } +/** + * @param {string} username + * @param {number|string} [expires] + */ +function makeToken(username, expires) { + let v = { + group: group, + }; + if(username) + v.username = username; + if(expires) + v.expires = expires; + else + v.expires = units.d; + if(serverConnection.permissions.indexOf('present') >= 0) + v.permissions = ['present']; + else + v.permissions = []; + serverConnection.groupAction('maketoken', v); +} + commands.invite = { predicate: makeTokenPredicate, description: "create an invitation link", parameters: "[username] [expiration]", f: (c, r) => { let p = parseCommand(r); - let v = { - group: group, - }; - if(p[0]) - v.username = p[0]; - if(p[1]) - v.expires = parseExpiration(p[1]); - else - v.expires = units.d; - if(serverConnection.permissions.indexOf('present') >= 0) - v.permissions = ['present']; - else - v.permissions = []; - serverConnection.groupAction('maketoken', v); + makeToken(p[0], parseExpiration(p[1])); } } diff --git a/token/stateful.go b/token/stateful.go index dfa3636..75ae327 100644 --- a/token/stateful.go +++ b/token/stateful.go @@ -355,3 +355,36 @@ func (state *state) List(group string) ([]*Stateful, error) { func List(group string) ([]*Stateful, error) { return tokens.List(group) } + +func (state *state) Expire() error { + state.mu.Lock() + defer state.mu.Unlock() + + err := state.load() + if err != nil { + return err + } + + now := time.Now() + cutoff := now.Add(-time.Hour * 24 * 7) + + modified := false + for k, t := range state.tokens { + if t.Expires.Before(cutoff) { + delete(state.tokens, k) + modified = true + } + } + + if modified { + err := state.rewrite() + if err != nil { + return err + } + } + return nil +} + +func Expire() error { + return tokens.Expire() +} diff --git a/token/stateful_test.go b/token/stateful_test.go index 4ba8212..962e22d 100644 --- a/token/stateful_test.go +++ b/token/stateful_test.go @@ -292,3 +292,71 @@ func TestTokenStorage(t *testing.T) { t.Errorf("existence check: %v", err) } } + +func TestExpire(t *testing.T) { + d := t.TempDir() + s := state{ + filename: filepath.Join(d, "test.jsonl"), + } + now := time.Now() + future := now.Add(time.Hour) + past := now.Add(-time.Hour * 24 * 6) + longPast := now.Add(-time.Hour * 24 * 8) + user := "user" + + tokens := []*Stateful{ + &Stateful{ + Token: "tok1", + Group: "test", + Username: &user, + Permissions: []string{"present"}, + Expires: &now, + }, + &Stateful{ + Token: "tok2", + Group: "test", + Username: &user, + Permissions: []string{"present"}, + Expires: &future, + }, + &Stateful{ + Token: "tok3", + Group: "test", + Username: &user, + Permissions: []string{"present"}, + Expires: &now, + }, + &Stateful{ + Token: "tok4", + Group: "test", + Username: &user, + Permissions: []string{"present"}, + Expires: &past, + }, + &Stateful{ + Token: "tok5", + Group: "test", + Username: &user, + Permissions: []string{"present"}, + Expires: &longPast, + }, + } + + for _, token := range tokens { + _, err := s.Add(token) + if err != nil { + t.Errorf("Add: %v", err) + } + } + + expectTokens(t, s.tokens, tokens) + expectTokenFile(t, s.filename, tokens) + + err := s.Expire() + if err != nil { + t.Errorf("Expire: %v", err) + } + + expectTokens(t, s.tokens, tokens[:len(tokens)-1]) + expectTokenFile(t, s.filename, tokens[:len(tokens)-1]) +}