get started with privacy modes, parse -mode flag
This commit is contained in:
parent
dafc341091
commit
faae7c0324
|
@ -34,6 +34,7 @@ import (
|
|||
"github.com/ssb-ngi-pointer/go-ssb-room/internal/network"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/internal/repo"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/internal/signinwithssb"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb/sqlite"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomsrv"
|
||||
mksrv "github.com/ssb-ngi-pointer/go-ssb-room/roomsrv"
|
||||
|
@ -53,6 +54,8 @@ var (
|
|||
logToFile string
|
||||
repoDir string
|
||||
|
||||
config roomdb.RoomConfig
|
||||
|
||||
// helper
|
||||
log kitlog.Logger
|
||||
|
||||
|
@ -81,9 +84,23 @@ func checkAndLog(err error) {
|
|||
}
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
// open, community, restricted
|
||||
privacyMode roomdb.PrivacyMode
|
||||
}
|
||||
|
||||
func (c Config) GetPrivacyMode(ctx context.Context) (roomdb.PrivacyMode, error) {
|
||||
err := c.privacyMode.IsValid()
|
||||
if err != nil {
|
||||
return roomdb.ModeUnknown, err
|
||||
}
|
||||
return c.privacyMode, nil
|
||||
}
|
||||
|
||||
func initFlags() {
|
||||
u, err := user.Current()
|
||||
checkFatal(err)
|
||||
config = Config{privacyMode: roomdb.ModeCommunity} // set default privacy mode to community
|
||||
|
||||
flag.StringVar(&appKey, "shscap", "1KHLiKZvAvjbY1ziZEHMXawbCEIM6qwjCDm3VYRan/s=", "secret-handshake app-key (or capability)")
|
||||
|
||||
|
@ -101,6 +118,16 @@ func initFlags() {
|
|||
|
||||
flag.BoolVar(&flagPrintVersion, "version", false, "print version number and build date")
|
||||
|
||||
flag.Func("mode", "the privacy mode (values: open, community, restricted) determining room access controls", func(val string) error {
|
||||
privacyMode := roomdb.ParsePrivacyMode(val)
|
||||
err := privacyMode.IsValid()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s, valid values are open, community, restricted", err)
|
||||
}
|
||||
config = Config{privacyMode: privacyMode}
|
||||
return nil
|
||||
})
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if logToFile != "" {
|
||||
|
@ -215,6 +242,7 @@ func runroomsrv() error {
|
|||
db.Aliases,
|
||||
db.AuthWithSSB,
|
||||
bridge,
|
||||
config,
|
||||
httpsDomain,
|
||||
opts...)
|
||||
if err != nil {
|
||||
|
@ -264,6 +292,7 @@ func runroomsrv() error {
|
|||
Aliases: db.Aliases,
|
||||
AuthFallback: db.AuthFallback,
|
||||
AuthWithSSB: db.AuthWithSSB,
|
||||
Config: config,
|
||||
DeniedKeys: db.DeniedKeys,
|
||||
Invites: db.Invites,
|
||||
Notices: db.Notices,
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"go.cryptoscope.co/muxrpc/v2"
|
||||
"go.cryptoscope.co/muxrpc/v2/typemux"
|
||||
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomstate"
|
||||
refs "go.mindeco.de/ssb-refs"
|
||||
)
|
||||
|
@ -22,11 +23,13 @@ import (
|
|||
}
|
||||
*/
|
||||
|
||||
func New(log kitlog.Logger, self refs.FeedRef, m *roomstate.Manager) *Handler {
|
||||
func New(log kitlog.Logger, self refs.FeedRef, m *roomstate.Manager, members roomdb.MembersService, config roomdb.RoomConfig) *Handler {
|
||||
var h = new(Handler)
|
||||
h.self = self
|
||||
h.logger = log
|
||||
h.state = m
|
||||
h.members = members
|
||||
h.config = config
|
||||
|
||||
return h
|
||||
}
|
||||
|
|
|
@ -5,9 +5,11 @@ package server
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/internal/network"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomstate"
|
||||
refs "go.mindeco.de/ssb-refs"
|
||||
|
||||
|
@ -20,7 +22,9 @@ type Handler struct {
|
|||
logger kitlog.Logger
|
||||
self refs.FeedRef
|
||||
|
||||
state *roomstate.Manager
|
||||
state *roomstate.Manager
|
||||
members roomdb.MembersService
|
||||
config roomdb.RoomConfig
|
||||
}
|
||||
|
||||
func (h *Handler) isRoom(context.Context, *muxrpc.Request) (interface{}, error) {
|
||||
|
@ -57,7 +61,7 @@ func (h *Handler) leave(_ context.Context, req *muxrpc.Request) (interface{}, er
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func (h *Handler) endpoints(_ context.Context, req *muxrpc.Request, snk *muxrpc.ByteSink) error {
|
||||
func (h *Handler) endpoints(ctx context.Context, req *muxrpc.Request, snk *muxrpc.ByteSink) error {
|
||||
level.Debug(h.logger).Log("called", "endpoints")
|
||||
|
||||
toPeer := newForwarder(snk)
|
||||
|
@ -70,6 +74,21 @@ func (h *Handler) endpoints(_ context.Context, req *muxrpc.Request, snk *muxrpc.
|
|||
return err
|
||||
}
|
||||
|
||||
pm, err := h.config.GetPrivacyMode(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("running with unknown privacy mode")
|
||||
}
|
||||
|
||||
switch pm {
|
||||
case roomdb.ModeCommunity:
|
||||
fallthrough
|
||||
case roomdb.ModeRestricted:
|
||||
_, err := h.members.GetByFeed(ctx, *ref)
|
||||
if err != nil {
|
||||
return fmt.Errorf("external user are not allowed to enumerate members")
|
||||
}
|
||||
}
|
||||
|
||||
has := h.state.AlreadyAdded(*ref, req.Endpoint())
|
||||
if !has {
|
||||
// just send the current state to the new peer
|
||||
|
|
|
@ -17,6 +17,10 @@ import (
|
|||
refs "go.mindeco.de/ssb-refs"
|
||||
)
|
||||
|
||||
type RoomConfig interface {
|
||||
GetPrivacyMode(context.Context) (PrivacyMode, error)
|
||||
}
|
||||
|
||||
// AuthFallbackService allows password authentication which might be helpful for scenarios
|
||||
// where one lost access to his ssb device or key.
|
||||
type AuthFallbackService interface {
|
||||
|
|
|
@ -33,6 +33,41 @@ type Member struct {
|
|||
PubKey refs.FeedRef
|
||||
}
|
||||
|
||||
//go:generate go run golang.org/x/tools/cmd/stringer -type=PrivacyMode
|
||||
|
||||
type PrivacyMode uint
|
||||
|
||||
func (pm PrivacyMode) IsValid() error {
|
||||
if pm == ModeUnknown || pm > ModeRestricted {
|
||||
return errors.New("No such privacy mode")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParsePrivacyMode(val string) PrivacyMode {
|
||||
switch val {
|
||||
case "open":
|
||||
return ModeOpen
|
||||
case "community":
|
||||
return ModeCommunity
|
||||
case "restricted":
|
||||
return ModeRestricted
|
||||
default:
|
||||
return ModeUnknown
|
||||
}
|
||||
}
|
||||
|
||||
// PrivacyMode describes the access mode the room server is currently running under.
|
||||
// ModeOpen allows anyone to create an room invite
|
||||
// ModeCommunity restricts invite creation to pre-existing room members (i.e. "internal users")
|
||||
// ModeRestricted only allows admins and moderators to create room invitations
|
||||
const (
|
||||
ModeUnknown PrivacyMode = iota
|
||||
ModeOpen
|
||||
ModeCommunity
|
||||
ModeRestricted
|
||||
)
|
||||
|
||||
//go:generate go run golang.org/x/tools/cmd/stringer -type=Role
|
||||
|
||||
// Role describes the authorization level of an internal user (or member).
|
||||
|
@ -42,7 +77,7 @@ type Role uint
|
|||
|
||||
func (r Role) IsValid() error {
|
||||
if r == RoleUnknown {
|
||||
return errors.New("uknown member role")
|
||||
return errors.New("unknown member role")
|
||||
}
|
||||
if r > RoleAdmin {
|
||||
return errors.New("invalid member role")
|
||||
|
|
|
@ -23,6 +23,8 @@ func (s *Server) initHandlers() {
|
|||
kitlog.With(s.logger, "unit", "tunnel"),
|
||||
s.Whoami(),
|
||||
s.StateManager,
|
||||
s.Members,
|
||||
s.Config,
|
||||
)
|
||||
|
||||
aliasHandler := alias.New(
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"go.cryptoscope.co/muxrpc/v2"
|
||||
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/internal/network"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
||||
)
|
||||
|
||||
// opens the shs listener for TCP connections
|
||||
|
@ -27,11 +28,20 @@ func (s *Server) initNetwork() error {
|
|||
return &s.master, nil
|
||||
}
|
||||
|
||||
if _, err := s.authorizer.GetByFeed(s.rootCtx, *remote); err == nil {
|
||||
return &s.public, nil
|
||||
pm, err := s.Config.GetPrivacyMode(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("running with unknown privacy mode")
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("not authorized")
|
||||
// if privacy mode is restricted, deny connections from non-members
|
||||
if pm == roomdb.ModeRestricted {
|
||||
if _, err := s.authorizer.GetByFeed(s.rootCtx, *remote); err != nil {
|
||||
return nil, fmt.Errorf("access restricted to members")
|
||||
}
|
||||
}
|
||||
|
||||
// for community + open modes, allow all connections
|
||||
return &s.public, nil
|
||||
}
|
||||
|
||||
// tcp+shs
|
||||
|
|
|
@ -70,6 +70,7 @@ type Server struct {
|
|||
|
||||
authWithSSB roomdb.AuthWithSSBService
|
||||
authWithSSBBridge *signinwithssb.SignalBridge
|
||||
Config roomdb.RoomConfig
|
||||
}
|
||||
|
||||
func (s Server) Whoami() refs.FeedRef {
|
||||
|
@ -81,6 +82,7 @@ func New(
|
|||
aliasdb roomdb.AliasesService,
|
||||
awsdb roomdb.AuthWithSSBService,
|
||||
bridge *signinwithssb.SignalBridge,
|
||||
config roomdb.RoomConfig,
|
||||
domainName string,
|
||||
opts ...Option,
|
||||
) (*Server, error) {
|
||||
|
@ -89,6 +91,7 @@ func New(
|
|||
|
||||
s.Members = membersdb
|
||||
s.Aliases = aliasdb
|
||||
s.Config = config
|
||||
|
||||
s.authWithSSB = awsdb
|
||||
s.authWithSSBBridge = bridge
|
||||
|
|
|
@ -44,6 +44,7 @@ var HTMLTemplates = []string{
|
|||
// Databases is an option struct that encapsualtes the required database services
|
||||
type Databases struct {
|
||||
Aliases roomdb.AliasesService
|
||||
Config roomdb.RoomConfig // cblgh: kind of confusing that we have two identically named structs, in different http handler contexts?
|
||||
DeniedKeys roomdb.DeniedKeysService
|
||||
Invites roomdb.InvitesService
|
||||
Notices roomdb.NoticesService
|
||||
|
@ -117,11 +118,13 @@ func Handler(
|
|||
mux.HandleFunc("/members/remove", mh.remove)
|
||||
|
||||
var ih = invitesHandler{
|
||||
r: r,
|
||||
db: dbs.Invites,
|
||||
r: r,
|
||||
db: dbs.Invites,
|
||||
config: dbs.Config,
|
||||
|
||||
domainName: domainName,
|
||||
}
|
||||
|
||||
mux.HandleFunc("/invites", r.HTML("admin/invite-list.tmpl", ih.overview))
|
||||
mux.HandleFunc("/invites/create", r.HTML("admin/invite-created.tmpl", ih.create))
|
||||
mux.HandleFunc("/invites/revoke/confirm", r.HTML("admin/invite-revoke-confirm.tmpl", ih.revokeConfirm))
|
||||
|
|
|
@ -19,7 +19,8 @@ import (
|
|||
type invitesHandler struct {
|
||||
r *render.Renderer
|
||||
|
||||
db roomdb.InvitesService
|
||||
db roomdb.InvitesService
|
||||
config roomdb.RoomConfig
|
||||
|
||||
domainName string
|
||||
}
|
||||
|
@ -58,6 +59,26 @@ func (h invitesHandler) create(w http.ResponseWriter, req *http.Request) (interf
|
|||
if member == nil {
|
||||
return nil, fmt.Errorf("warning: no user session for elevated access request")
|
||||
}
|
||||
pm, err := h.config.GetPrivacyMode(req.Context())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
/* We want to check:
|
||||
* 1. the room's privacy mode
|
||||
* 2. the role of the member trying to create the invite
|
||||
* and deny unallowed requests (e.g. member creating invite in ModeRestricted)
|
||||
*/
|
||||
switch pm {
|
||||
case roomdb.ModeOpen:
|
||||
case roomdb.ModeCommunity:
|
||||
if member.Role == roomdb.RoleUnknown {
|
||||
return nil, fmt.Errorf("warning: member with unknown role tried to create an invite")
|
||||
}
|
||||
case roomdb.ModeRestricted:
|
||||
if member.Role == roomdb.RoleMember || member.Role == roomdb.RoleUnknown {
|
||||
return nil, fmt.Errorf("warning: non-admin/mod user tried to create an invite")
|
||||
}
|
||||
}
|
||||
|
||||
token, err := h.db.Create(req.Context(), member.ID)
|
||||
if err != nil {
|
||||
|
|
|
@ -21,12 +21,13 @@ import (
|
|||
type aliasHandler struct {
|
||||
r *render.Renderer
|
||||
|
||||
db roomdb.AliasesService
|
||||
db roomdb.AliasesService
|
||||
config roomdb.RoomConfig
|
||||
|
||||
roomEndpoint network.ServerEndpointDetails
|
||||
}
|
||||
|
||||
func (a aliasHandler) resolve(rw http.ResponseWriter, req *http.Request) {
|
||||
func (h aliasHandler) resolve(rw http.ResponseWriter, req *http.Request) {
|
||||
respEncoding := req.URL.Query().Get("encoding")
|
||||
|
||||
var ar aliasResponder
|
||||
|
@ -34,18 +35,28 @@ func (a aliasHandler) resolve(rw http.ResponseWriter, req *http.Request) {
|
|||
case "json":
|
||||
ar = newAliasJSONResponder(rw)
|
||||
default:
|
||||
ar = newAliasHTMLResponder(a.r, rw, req)
|
||||
ar = newAliasHTMLResponder(h.r, rw, req)
|
||||
}
|
||||
|
||||
ar.UpdateRoomInfo(a.roomEndpoint)
|
||||
|
||||
pm, err := h.config.GetPrivacyMode(req.Context())
|
||||
if err != nil {
|
||||
ar.SendError(fmt.Errorf("room is running an unknown privacy mode"))
|
||||
return
|
||||
}
|
||||
if pm == roomdb.ModeRestricted {
|
||||
ar.SendError(fmt.Errorf("this room is restricted, alias resolving is turned off"))
|
||||
return
|
||||
}
|
||||
|
||||
name := mux.Vars(req)["alias"]
|
||||
if name == "" && !aliases.IsValid(name) {
|
||||
ar.SendError(fmt.Errorf("invalid alias"))
|
||||
return
|
||||
}
|
||||
|
||||
alias, err := a.db.Resolve(req.Context(), name)
|
||||
alias, err := h.db.Resolve(req.Context(), name)
|
||||
if err != nil {
|
||||
ar.SendError(fmt.Errorf("aliases: failed to resolve name %q: %w", name, err))
|
||||
return
|
||||
|
|
|
@ -53,6 +53,7 @@ type Databases struct {
|
|||
Aliases roomdb.AliasesService
|
||||
AuthFallback roomdb.AuthFallbackService
|
||||
AuthWithSSB roomdb.AuthWithSSBService
|
||||
Config roomdb.RoomConfig
|
||||
DeniedKeys roomdb.DeniedKeysService
|
||||
Invites roomdb.InvitesService
|
||||
Notices roomdb.NoticesService
|
||||
|
@ -260,6 +261,7 @@ func New(
|
|||
roomState,
|
||||
admin.Databases{
|
||||
Aliases: dbs.Aliases,
|
||||
Config: dbs.Config,
|
||||
DeniedKeys: dbs.DeniedKeys,
|
||||
Invites: dbs.Invites,
|
||||
Notices: dbs.Notices,
|
||||
|
@ -294,7 +296,8 @@ func New(
|
|||
var ah = aliasHandler{
|
||||
r: r,
|
||||
|
||||
db: dbs.Aliases,
|
||||
db: dbs.Aliases,
|
||||
config: dbs.Config,
|
||||
|
||||
roomEndpoint: netInfo,
|
||||
}
|
||||
|
@ -303,8 +306,8 @@ func New(
|
|||
var ih = inviteHandler{
|
||||
render: r,
|
||||
|
||||
invites: dbs.Invites,
|
||||
pinnedNotices: dbs.PinnedNotices,
|
||||
config: dbs.Config,
|
||||
invites: dbs.Invites,
|
||||
|
||||
networkInfo: netInfo,
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ type inviteHandler struct {
|
|||
|
||||
invites roomdb.InvitesService
|
||||
pinnedNotices roomdb.PinnedNoticesService
|
||||
config roomdb.RoomConfig
|
||||
|
||||
networkInfo network.ServerEndpointDetails
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue