diff --git a/cmd/server/main.go b/cmd/server/main.go index 8d103c7..9096d62 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -50,6 +50,8 @@ var ( httpsDomain string + aliasesAsSubdomains bool + listenAddrDebug string logToFile string repoDir string @@ -114,6 +116,8 @@ func initFlags() { return nil }) + flag.BoolVar(&aliasesAsSubdomains, "aliases-as-subdomains", true, "needs to be disabled if a wildcard certificate for the room is not available. (stub until we have the admin/settings page)") + flag.Parse() if logToFile != "" { @@ -153,7 +157,7 @@ func runroomsrv() error { return fmt.Errorf("invalid muxrpc listener: %w", err) } - portMUXRPC, err := net.LookupPort("tcp", muxrpcPortStr) + _, err = net.LookupPort("tcp", muxrpcPortStr) if err != nil { return fmt.Errorf("invalid tcp port for muxrpc listener: %w", err) } @@ -180,7 +184,6 @@ func runroomsrv() error { roomsrv.WithLogger(log), roomsrv.WithAppKey(ak), roomsrv.WithRepoPath(repoDir), - roomsrv.WithListenAddr(listenAddrShsMux), roomsrv.WithUNIXSocket(!flagDisableUNIXSock), } @@ -214,6 +217,23 @@ func runroomsrv() error { r := repo.New(repoDir) + keyPair, err := repo.DefaultKeyPair(r) + checkAndLog(err) + opts = append(opts, roomsrv.WithKeyPair(keyPair)) + + networkInfo := network.ServerEndpointDetails{ + Development: development, + + Domain: httpsDomain, + PortHTTPS: uint(portHTTP), + + RoomID: keyPair.Feed, + + ListenAddressMUXRPC: listenAddrShsMux, + + UseSubdomainForAliases: aliasesAsSubdomains, + } + // open the sqlite version of the roomdb db, err := sqlite.Open(r) if err != nil { @@ -234,7 +254,7 @@ func runroomsrv() error { db.AuthWithSSB, bridge, db.Config, - httpsDomain, + networkInfo, opts...) if err != nil { return fmt.Errorf("failed to instantiate ssb server: %w", err) @@ -268,14 +288,7 @@ func runroomsrv() error { webHandler, err := handlers.New( kitlog.With(log, "package", "web"), repo.New(repoDir), - network.ServerEndpointDetails{ - Domain: httpsDomain, - PortHTTPS: uint(portHTTP), - PortMUXRPC: uint(portMUXRPC), - RoomID: roomsrv.Whoami(), - - Development: development, - }, + networkInfo, roomsrv.StateManager, roomsrv.Network, bridge, diff --git a/internal/network/interface.go b/internal/network/interface.go index 490ba11..533fe98 100644 --- a/internal/network/interface.go +++ b/internal/network/interface.go @@ -10,6 +10,7 @@ import ( "io" "net" "net/http" + "net/url" "time" "go.cryptoscope.co/muxrpc/v2" @@ -21,21 +22,52 @@ import ( // ServerEndpointDetails encapsulates the endpoint information. // Like domain name of the room, it's ssb/secret-handshake public key and the HTTP and MUXRPC TCP ports. type ServerEndpointDetails struct { - PortMUXRPC uint - PortHTTPS uint // 0 assumes default (443) - RoomID refs.FeedRef - Domain string + ListenAddressMUXRPC string // defaults to ":8008" + // Domain sets the DNS name for all the HTTP(S) URLs. + Domain string + PortHTTPS uint // 0 assumes default (443) + + // UseSubdomainForAliases controls wether urls for alias resolving + // are generated as https://$alias.$domain instead of https://$domain/alias/$alias + UseSubdomainForAliases bool + + // Development instructs url building to happen with http and include the http port Development bool } +func (sed ServerEndpointDetails) URLForAlias(a string) string { + var u url.URL + + if sed.Development { + u.Path = "/alias/" + a + u.Scheme = "http" + u.Host = fmt.Sprintf("localhost:%d", sed.PortHTTPS) + return u.String() + } + + u.Scheme = "https" + + if sed.UseSubdomainForAliases { + u.Host = a + "." + sed.Domain + } else { + u.Path = "/alias/" + a + } + + return u.String() +} + // MultiserverAddress returns net:domain:muxport~shs:roomPubKeyInBase64 // ie: the room servers https://github.com/ssbc/multiserver-address func (sed ServerEndpointDetails) MultiserverAddress() string { + addr, err := net.ResolveTCPAddr("tcp", sed.ListenAddressMUXRPC) + if err != nil { + panic(err) + } var roomPubKey = base64.StdEncoding.EncodeToString(sed.RoomID.PubKey()) - return fmt.Sprintf("net:%s:%d~shs:%s", sed.Domain, sed.PortMUXRPC, roomPubKey) + return fmt.Sprintf("net:%s:%d~shs:%s", sed.Domain, addr.Port, roomPubKey) } // EndpointStat gives some information about a connected peer diff --git a/internal/network/msaddr_test.go b/internal/network/msaddr_test.go index e2cb8db..38fdfee 100644 --- a/internal/network/msaddr_test.go +++ b/internal/network/msaddr_test.go @@ -15,7 +15,7 @@ func TestMultiserverAddress(t *testing.T) { var sed ServerEndpointDetails sed.Domain = "the.ho.st" - sed.PortMUXRPC = 8008 + sed.ListenAddressMUXRPC = ":8008" sed.RoomID = refs.FeedRef{ ID: bytes.Repeat([]byte("ohai"), 8), diff --git a/muxrpc/handlers/alias/handler.go b/muxrpc/handlers/alias/handler.go index cb2be67..a63c30c 100644 --- a/muxrpc/handlers/alias/handler.go +++ b/muxrpc/handlers/alias/handler.go @@ -27,15 +27,17 @@ type Handler struct { db roomdb.AliasesService - roomDomain string // the http(s) domain of the room to signal alias addresses + netInfo network.ServerEndpointDetails + + // roomDomain string // the http(s) domain of the room to signal alias addresses } // New returns a fresh alias muxrpc handler -func New(log kitlog.Logger, self refs.FeedRef, aliasesDB roomdb.AliasesService, roomDomain string) Handler { +func New(log kitlog.Logger, self refs.FeedRef, aliasesDB roomdb.AliasesService, netInfo network.ServerEndpointDetails) Handler { var h Handler h.self = self - h.roomDomain = roomDomain + h.netInfo = netInfo h.logger = log h.db = aliasesDB @@ -100,14 +102,7 @@ func (h Handler) Register(ctx context.Context, req *muxrpc.Request) (interface{} return nil, fmt.Errorf("registerAlias: could not register alias: %w", err) } - resolveURL, err := httpRouter.Get(router.CompleteAliasResolve).URL("alias", confirmation.Alias) - if err != nil { - return nil, err - } - resolveURL.Host = h.roomDomain - resolveURL.Scheme = "https" - - return resolveURL.String(), nil + return h.netInfo.URLForAlias(confirmation.Alias), nil } // Revoke checks that the alias is from that user before revoking the alias from the database. diff --git a/muxrpc/test/go/utils_test.go b/muxrpc/test/go/utils_test.go index f6523d3..d2d3548 100644 --- a/muxrpc/test/go/utils_test.go +++ b/muxrpc/test/go/utils_test.go @@ -79,7 +79,6 @@ func makeNamedTestBot(t testing.TB, name string, opts []roomsrv.Option) (roomdb. botOptions := append(opts, roomsrv.WithLogger(log.With(mainLog, "bot", name)), roomsrv.WithRepoPath(testPath), - roomsrv.WithListenAddr(":0"), roomsrv.WithNetworkConnTracker(network.NewLastWinsTracker()), roomsrv.WithPostSecureConnWrapper(func(conn net.Conn) (net.Conn, error) { return debug.WrapDump(filepath.Join(testPath, "muxdump"), conn) @@ -98,8 +97,14 @@ func makeNamedTestBot(t testing.TB, name string, opts []roomsrv.Option) (roomdb. err = db.Config.SetPrivacyMode(context.TODO(), roomdb.ModeRestricted) r.NoError(err) + netInfo := network.ServerEndpointDetails{ + Domain: name, + + ListenAddressMUXRPC: ":0", + } + sb := signinwithssb.NewSignalBridge() - theBot, err := roomsrv.New(db.Members, db.DeniedKeys, db.Aliases, db.AuthWithSSB, sb, db.Config, name, botOptions...) + theBot, err := roomsrv.New(db.Members, db.DeniedKeys, db.Aliases, db.AuthWithSSB, sb, db.Config, netInfo, botOptions...) r.NoError(err) return db.Members, theBot } diff --git a/muxrpc/test/nodejs/setup_test.go b/muxrpc/test/nodejs/setup_test.go index 53dbc65..e3c7ea1 100644 --- a/muxrpc/test/nodejs/setup_test.go +++ b/muxrpc/test/nodejs/setup_test.go @@ -96,10 +96,15 @@ func (ts *testSession) startGoServer( ) *roomsrv.Server { r := require.New(ts.t) + netInfo := network.ServerEndpointDetails{ + Domain: "go.test.room.server", + + ListenAddressMUXRPC: "localhost:0", + } + // prepend defaults opts = append([]roomsrv.Option{ roomsrv.WithLogger(ts.info), - roomsrv.WithListenAddr("localhost:0"), roomsrv.WithRepoPath(ts.repo), roomsrv.WithContext(ts.ctx), }, opts...) @@ -126,7 +131,7 @@ func (ts *testSession) startGoServer( fakeConfig := new(mockdb.FakeRoomConfig) deniedKeysDB := new(mockdb.FakeDeniedKeysService) - srv, err := roomsrv.New(membersDB, deniedKeysDB, aliasDB, authSessionsDB, sb, fakeConfig, "go.test.room.server", opts...) + srv, err := roomsrv.New(membersDB, deniedKeysDB, aliasDB, authSessionsDB, sb, fakeConfig, netInfo, opts...) r.NoError(err, "failed to init tees a server") ts.t.Logf("go server: %s", srv.Whoami().Ref()) ts.t.Cleanup(func() { diff --git a/roomsrv/init_handlers.go b/roomsrv/init_handlers.go index de01406..b677c14 100644 --- a/roomsrv/init_handlers.go +++ b/roomsrv/init_handlers.go @@ -31,13 +31,13 @@ func (s *Server) initHandlers() { kitlog.With(s.logger, "unit", "aliases"), s.Whoami(), s.Aliases, - s.domain, + s.netInfo, ) siwssbHandler := signinwithssb.New( kitlog.With(s.logger, "unit", "auth-with-ssb"), s.Whoami(), - s.domain, + s.netInfo.Domain, s.Members, s.authWithSSB, s.authWithSSBBridge, diff --git a/roomsrv/options.go b/roomsrv/options.go index 56830c7..6fa8931 100644 --- a/roomsrv/options.go +++ b/roomsrv/options.go @@ -5,7 +5,6 @@ package roomsrv import ( "context" "fmt" - "net" "strings" kitlog "github.com/go-kit/kit/log" @@ -108,18 +107,6 @@ func WithNetworkConnTracker(ct network.ConnTracker) Option { } } -// WithListenAddr changes the muxrpc listener address. By default it listens to ':8008'. -func WithListenAddr(addr string) Option { - return func(s *Server) error { - var err error - s.listenAddr, err = net.ResolveTCPAddr("tcp", addr) - if err != nil { - return fmt.Errorf("failed to parse tcp listen addr: %w", err) - } - return nil - } -} - // WithPreSecureConnWrapper wrapps the connection after it is encrypted. // Usefull for debugging and measuring traffic. func WithPreSecureConnWrapper(cw netwrap.ConnWrapper) Option { diff --git a/roomsrv/server.go b/roomsrv/server.go index 77cced8..b1906e8 100644 --- a/roomsrv/server.go +++ b/roomsrv/server.go @@ -46,7 +46,7 @@ type Server struct { wsAddr string dialer netwrap.Dialer - domain string // the DNS domain name of the room + netInfo network.ServerEndpointDetails loadUnixSock bool @@ -85,7 +85,7 @@ func New( awsdb roomdb.AuthWithSSBService, bridge *signinwithssb.SignalBridge, config roomdb.RoomConfig, - domainName string, + netInfo network.ServerEndpointDetails, opts ...Option, ) (*Server, error) { var s Server @@ -99,7 +99,7 @@ func New( s.authWithSSB = awsdb s.authWithSSBBridge = bridge - s.domain = domainName + s.netInfo = netInfo for i, opt := range opts { err := opt(&s) @@ -129,8 +129,10 @@ func New( s.dialer = netwrap.Dial } - if s.listenAddr == nil { - s.listenAddr = &net.TCPAddr{Port: network.DefaultPort} + var err error + s.listenAddr, err = net.ResolveTCPAddr("tcp", s.netInfo.ListenAddressMUXRPC) + if err != nil { + return nil, err } if s.logger == nil { @@ -152,7 +154,7 @@ func New( var err error s.keyPair, err = repo.DefaultKeyPair(s.repo) if err != nil { - return nil, fmt.Errorf("sbot: failed to get keypair: %w", err) + return nil, fmt.Errorf("roomsrv: failed to get keypair: %w", err) } } diff --git a/web/handlers/admin/handler.go b/web/handlers/admin/handler.go index 77dc2b2..49e8097 100644 --- a/web/handlers/admin/handler.go +++ b/web/handlers/admin/handler.go @@ -118,6 +118,7 @@ func Handler( r: r, flashes: fh, urlTo: urlTo, + netInfo: netInfo, db: dbs.Members, } diff --git a/web/handlers/admin/members.go b/web/handlers/admin/members.go index b31620e..cab0f1f 100644 --- a/web/handlers/admin/members.go +++ b/web/handlers/admin/members.go @@ -5,24 +5,27 @@ package admin import ( "errors" "fmt" + "html/template" "net/http" "strconv" - "go.mindeco.de/http/render" - refs "go.mindeco.de/ssb-refs" - "github.com/gorilla/csrf" + "go.mindeco.de/http/render" + + "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/web" weberrors "github.com/ssb-ngi-pointer/go-ssb-room/web/errors" "github.com/ssb-ngi-pointer/go-ssb-room/web/members" "github.com/ssb-ngi-pointer/go-ssb-room/web/router" + refs "go.mindeco.de/ssb-refs" ) type membersHandler struct { r *render.Renderer flashes *weberrors.FlashHelper urlTo web.URLMaker + netInfo network.ServerEndpointDetails db roomdb.MembersService } @@ -149,9 +152,15 @@ func (h membersHandler) details(rw http.ResponseWriter, req *http.Request) (inte roles := []roomdb.Role{roomdb.RoleMember, roomdb.RoleModerator, roomdb.RoleAdmin} + aliasURLs := make(map[string]template.URL) + for _, a := range member.Aliases { + aliasURLs[a.Name] = template.URL(h.netInfo.URLForAlias(a.Name)) + } + return map[string]interface{}{ "Member": member, "AllRoles": roles, + "AliasURLs": aliasURLs, csrf.TemplateTag: csrf.TemplateField(req), }, nil } diff --git a/web/handlers/admin/members_test.go b/web/handlers/admin/members_test.go index 1aa937a..0d870f4 100644 --- a/web/handlers/admin/members_test.go +++ b/web/handlers/admin/members_test.go @@ -2,6 +2,7 @@ package admin import ( "bytes" + "fmt" "net/http" "net/url" "testing" @@ -192,8 +193,9 @@ func TestMemberDetails(t *testing.T) { // check for link to resolve 1st Alias aliasRobertLink, yes := aliasList.Eq(0).Attr("href") a.True(yes, "a-tag has href attribute") - // TODO: fix wildcard domain - a.Equal("/alias/robert", aliasRobertLink) + + wantURL := fmt.Sprintf("https://robert.%s", ts.netInfo.Domain) + a.Equal(wantURL, aliasRobertLink) // check for link to revoke 1st Alias revokeRobertLink, yes := aliasList.Eq(1).Attr("href") @@ -204,8 +206,8 @@ func TestMemberDetails(t *testing.T) { // check for link to resolve 1st Alias aliasBobLink, yes := aliasList.Eq(2).Attr("href") a.True(yes, "a-tag has href attribute") - // TODO: fix wildcard domain - a.Equal("/alias/bob", aliasBobLink) + wantURL = fmt.Sprintf("https://bob.%s", ts.netInfo.Domain) + a.Equal(wantURL, aliasBobLink) // check for link to revoke 1st Alias revokeBobLink, yes := aliasList.Eq(3).Attr("href") diff --git a/web/handlers/admin/setup_test.go b/web/handlers/admin/setup_test.go index fc0cbdd..438be69 100644 --- a/web/handlers/admin/setup_test.go +++ b/web/handlers/admin/setup_test.go @@ -77,6 +77,8 @@ func newSession(t *testing.T) *testSession { ts.netInfo = network.ServerEndpointDetails{ Domain: randutil.String(10), RoomID: refs.FeedRef{Algo: "ed25519", ID: bytes.Repeat([]byte{0}, 32)}, + + UseSubdomainForAliases: true, } // instantiate the urlTo helper (constructs urls for us!) diff --git a/web/handlers/setup_test.go b/web/handlers/setup_test.go index a4947a1..16b708c 100644 --- a/web/handlers/setup_test.go +++ b/web/handlers/setup_test.go @@ -83,9 +83,10 @@ func setup(t *testing.T) *testSession { ts.MockedEndpoints = new(mocked.FakeEndpoints) ts.NetworkInfo = network.ServerEndpointDetails{ - Domain: "localhost", - PortMUXRPC: 8008, - PortHTTPS: 443, + Domain: "localhost", + PortHTTPS: 443, + + ListenAddressMUXRPC: ":8008", RoomID: refs.FeedRef{ ID: bytes.Repeat([]byte("test"), 8), diff --git a/web/templates/admin/member.tmpl b/web/templates/admin/member.tmpl index f955a4e..b89301e 100644 --- a/web/templates/admin/member.tmpl +++ b/web/templates/admin/member.tmpl @@ -54,7 +54,7 @@ {{range .Member.Aliases}}
{{.Name}}