Skip to content

Commit

Permalink
Support open invites (fixes #102)
Browse files Browse the repository at this point in the history
  • Loading branch information
cryptix committed May 14, 2021
1 parent 385b98a commit 20965a9
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 7 deletions.
2 changes: 1 addition & 1 deletion roomdb/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ type AliasesService interface {
// InvitesService manages creation and consumption of invite tokens for joining the room.
type InvitesService interface {
// Create creates a new invite for a new member. It returns the token or an error.
// createdBy is user ID of the admin or moderator who created it.
// createdBy is user ID of the admin or moderator who created it. MemberID -1 is allowed if Privacy Mode is set to Open.
// aliasSuggestion is optional (empty string is fine) but can be used to disambiguate open invites. (See https://github.com/ssb-ngi-pointer/rooms2/issues/21)
Create(ctx context.Context, createdBy int64) (string, error)

Expand Down
23 changes: 20 additions & 3 deletions roomdb/sqlite/invites.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,23 @@ func (i Invites) Create(ctx context.Context, createdBy int64) (string, error) {

err := transact(i.db, func(tx *sql.Tx) error {

if createdBy == -1 {
config, err := models.FindConfig(ctx, tx, configRowID)
if err != nil {
return err
}

if config.PrivacyMode != roomdb.ModeOpen {
return fmt.Errorf("roomdb: privacy mode not set to open but %s", config.PrivacyMode.String())
}

m, err := models.Members(qm.Where("role = ?", roomdb.RoleAdmin)).One(ctx, tx)
if err != nil {
return err
}
newInvite.CreatedBy = m.ID
}

inserted := false
trying:
for tries := 100; tries > 0; tries-- {
Expand All @@ -68,7 +85,7 @@ func (i Invites) Create(ctx context.Context, createdBy int64) (string, error) {
}

if !inserted {
return errors.New("admindb: failed to generate an invite token in a reasonable amount of time")
return errors.New("roomdb: failed to generate an invite token in a reasonable amount of time")
}

return nil
Expand Down Expand Up @@ -139,7 +156,7 @@ func (i Invites) Consume(ctx context.Context, token string, newMember refs.FeedR
func deleteConsumedInvites(tx boil.ContextExecutor) error {
_, err := models.Invites(qm.Where("active = false")).DeleteAll(context.Background(), tx)
if err != nil {
return fmt.Errorf("admindb: failed to delete used invites: %w", err)
return fmt.Errorf("roomdb: failed to delete used invites: %w", err)
}
return nil
}
Expand Down Expand Up @@ -269,7 +286,7 @@ func getHashedToken(b64tok string) (string, error) {
}

if n := len(tokenBytes); n != inviteTokenLength {
return "", fmt.Errorf("admindb: invalid invite token length (only got %d bytes)", n)
return "", fmt.Errorf("roomdb: invalid invite token length (only got %d bytes)", n)
}

// hash the binary of the passed token
Expand Down
2 changes: 0 additions & 2 deletions web/handlers/admin/invites.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ func (h invitesHandler) create(w http.ResponseWriter, req *http.Request) (interf
}

facadeURL := h.urlTo(router.CompleteInviteFacade, "token", token)
facadeURL.Host = h.domainName
facadeURL.Scheme = "https"

return map[string]interface{}{
"FacadeURL": facadeURL.String(),
Expand Down
12 changes: 12 additions & 0 deletions web/handlers/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@ func New(
render.SetErrorHandler(eh.Handle),
render.FuncMap(web.TemplateFuncs(m, netInfo)),

render.InjectTemplateFunc("privacy_mode_is", func(r *http.Request) interface{} {
return func(want string) bool {
has, err := dbs.Config.GetPrivacyMode(r.Context())
if err != nil {
return false
}
fmt.Println(has.String())
return has.String() == want
}
}),

render.InjectTemplateFunc("current_page_is", func(r *http.Request) interface{} {
return func(routeName string) bool {
route := m.Get(routeName)
Expand Down Expand Up @@ -351,6 +362,7 @@ func New(
m.Get(router.CompleteInviteFacadeFallback).Handler(r.HTML("invite/facade-fallback.tmpl", ih.presentFacadeFallback))
m.Get(router.CompleteInviteInsertID).Handler(r.HTML("invite/insert-id.tmpl", ih.presentInsert))
m.Get(router.CompleteInviteConsume).HandlerFunc(ih.consume)
m.Get(router.OpenModeCreateInvite).HandlerFunc(r.HTML("admin/invite-created.tmpl", ih.createOpenMode))

// static assets
m.PathPrefix("/assets/").Handler(http.StripPrefix("/assets/", http.FileServer(web.Assets)))
Expand Down
15 changes: 15 additions & 0 deletions web/handlers/invites.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,18 @@ func (html inviteConsumeHTMLResponder) SendSuccess() {
func (html inviteConsumeHTMLResponder) SendError(err error) {
html.renderer.Error(html.rw, html.req, http.StatusInternalServerError, err)
}

func (h inviteHandler) createOpenMode(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
ctx := req.Context()

token, err := h.invites.Create(ctx, -1)
if err != nil {
return nil, err
}

facadeURL := h.urlTo(router.CompleteInviteFacade, "token", token)

return map[string]interface{}{
"FacadeURL": facadeURL.String(),
}, nil
}
9 changes: 8 additions & 1 deletion web/i18n/defaults/active.de.toml
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ AdminInviteSuggestedAliasIs = "Der vorgeschlagene Alias ​​lautet:"
AdminInviteSuggestedAliasIsShort = "Alias:"

AdminInviteCreatedTitle = "Einladung erfolgreich erstellt!"
AdminInviteCreatedInstruct = "Kopieren Sie nun den folgenden Link und fügen Sie ihn in einen Freund ein, den Sie in diesen Raum einladen möchten."
AdminInviteCreatedInstruct = "Kopieren Sie nun den folgenden Link und geben Sie ihn an den Entfänger weiter, den Sie in diesen Raum einladen möchten."

# public invites
################
Expand All @@ -183,6 +183,13 @@ InviteInsertWelcome = "Sie können Ihre Einladung anfordern, indem Sie unten Ihr
InviteConsumedTitle = "Einladung angenommen!"
InviteConsumedWelcome = "Sie sind jetzt Mitglied dieses Raums. Wenn Sie eine Multiserver-Adresse benötigen, um eine Verbindung zum Raum herzustellen, können Sie die folgende kopieren und einfügen:"

# ssb uri links
###############

SSBURIOpening = "SSB App öffnen "
SSBURIFailureWelcome = "Sind Sie neu bei SSB? Es scheint, dass Sie keine SSB-App haben, die diesen Link verstehen kann. Sie können eine dieser Apps installieren: "
SSBURIFailureInstallManyverse = "Manyverse Installieren"

# notices (mini-CMS)
####################

Expand Down
3 changes: 3 additions & 0 deletions web/router/complete.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const (

MembersChangePasswordForm = "members:change-password:form"
MembersChangePassword = "members:change-password"

OpenModeCreateInvite = "open:invites:create"
)

// CompleteApp constructs a mux.Router containing the routes for batch Complete html frontend
Expand All @@ -40,6 +42,7 @@ func CompleteApp() *mux.Router {
m.Path("/members/change-password").Methods("GET").Name(MembersChangePasswordForm)
m.Path("/members/change-password").Methods("POST").Name(MembersChangePassword)

m.Path("/create-invite").Methods("GET").Name(OpenModeCreateInvite)
m.Path("/join").Methods("GET").Name(CompleteInviteFacade)
m.Path("/join-fallback").Methods("GET").Name(CompleteInviteFacadeFallback)
m.Path("/join-manually").Methods("GET").Name(CompleteInviteInsertID)
Expand Down
6 changes: 6 additions & 0 deletions web/templates/base.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
>{{i18n "AuthSignOut"}}</a>
</span>
{{else}}
{{if privacy_mode_is "ModeOpen"}}
<a
href="{{urlTo "open:invites:create"}}"
class="pl-3 pr-4 py-2 sm:py-1 font-semibold text-sm text-gray-500 hover:text-green-500"
>i18n "CreateInvite"</a>
{{end}}
<a
href="{{urlTo "auth:login"}}"
class="pl-3 pr-4 py-2 sm:py-1 font-semibold text-sm text-gray-500 hover:text-green-500"
Expand Down

0 comments on commit 20965a9

Please sign in to comment.