Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nodeinfo compliance #61

Merged
merged 1 commit into from
Jun 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 0 additions & 39 deletions internal/api/model/webfinger.go

This file was deleted.

78 changes: 78 additions & 0 deletions internal/api/model/well-known.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
GoToSocial
Copyright (C) 2021 GoToSocial Authors [email protected]

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package model

// WellKnownResponse represents the response to either a webfinger request for an 'acct' resource, or a request to nodeinfo.
// For example, it would be returned from https://example.org/.well-known/webfinger?resource=acct:[email protected]
//
// See https://webfinger.net/
type WellKnownResponse struct {
Subject string `json:"subject,omitempty"`
Aliases []string `json:"aliases,omitempty"`
Links []Link `json:"links,omitempty"`
}

// Link represents one 'link' in a slice of links returned from a lookup request.
//
// See https://webfinger.net/
type Link struct {
Rel string `json:"rel"`
Type string `json:"type,omitempty"`
Href string `json:"href,omitempty"`
Template string `json:"template,omitempty"`
}

// Nodeinfo represents a version 2.1 or version 2.0 nodeinfo schema.
// See: https://nodeinfo.diaspora.software/schema.html
type Nodeinfo struct {
// The schema version
Version string `json:"version"`
// Metadata about server software in use.
Software NodeInfoSoftware `json:"software"`
// The protocols supported on this server.
Protocols []string `json:"protocols"`
// The third party sites this server can connect to via their application API.
Services NodeInfoServices `json:"services"`
// Whether this server allows open self-registration.
OpenRegistrations bool `json:"openRegistrations"`
// Usage statistics for this server.
Usage NodeInfoUsage `json:"usage"`
// Free form key value pairs for software specific values. Clients should not rely on any specific key present.
Metadata map[string]interface{} `json:"metadata"`
}

// NodeInfoSoftware represents the name and version number of the software of this node.
type NodeInfoSoftware struct {
Name string `json:"name"`
Version string `json:"version"`
}

// NodeInfoServices represents inbound and outbound services that this node offers connections to.
type NodeInfoServices struct {
Inbound []string `json:"inbound"`
Outbound []string `json:"outbound"`
}

// NodeInfoUsage represents usage information about this server, such as number of users.
type NodeInfoUsage struct {
Users NodeInfoUsers `json:"users"`
}

// NodeInfoUsers is a stub for usage information, currently empty.
type NodeInfoUsers struct{}
59 changes: 59 additions & 0 deletions internal/api/s2s/nodeinfo/nodeinfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
GoToSocial
Copyright (C) 2021 GoToSocial Authors [email protected]

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package nodeinfo

import (
"net/http"

"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)

const (
// NodeInfoWellKnownPath is the base path for serving responses to nodeinfo lookup requests.
NodeInfoWellKnownPath = ".well-known/nodeinfo"
// NodeInfoBasePath is the path for serving nodeinfo responses.
NodeInfoBasePath = "/nodeinfo/2.0"
)

// Module implements the FederationModule interface
type Module struct {
config *config.Config
processor processing.Processor
log *logrus.Logger
}

// New returns a new nodeinfo module
func New(config *config.Config, processor processing.Processor, log *logrus.Logger) api.FederationModule {
return &Module{
config: config,
processor: processor,
log: log,
}
}

// Route satisfies the FederationModule interface
func (m *Module) Route(s router.Router) error {
s.AttachHandler(http.MethodGet, NodeInfoWellKnownPath, m.NodeInfoWellKnownGETHandler)
s.AttachHandler(http.MethodGet, NodeInfoBasePath, m.NodeInfoGETHandler)
return nil
}
44 changes: 44 additions & 0 deletions internal/api/s2s/nodeinfo/nodeinfoget.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
GoToSocial
Copyright (C) 2021 GoToSocial Authors [email protected]

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package nodeinfo

import (
"net/http"

"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)

// NodeInfoGETHandler returns a compliant nodeinfo response to node info queries.
// See: https://nodeinfo.diaspora.software/
func (m *Module) NodeInfoGETHandler(c *gin.Context) {
l := m.log.WithFields(logrus.Fields{
"func": "NodeInfoGETHandler",
"user-agent": c.Request.UserAgent(),
})

ni, err := m.processor.GetNodeInfo(c.Request)
if err != nil {
l.Debugf("error with get node info request: %s", err)
c.JSON(err.Code(), err.Safe())
return
}

c.JSON(http.StatusOK, ni)
}
44 changes: 44 additions & 0 deletions internal/api/s2s/nodeinfo/wellknownget.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
GoToSocial
Copyright (C) 2021 GoToSocial Authors [email protected]

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package nodeinfo

import (
"net/http"

"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)

// NodeInfoWellKnownGETHandler returns a well known response to a query to /.well-known/nodeinfo,
// directing (but not redirecting...) callers to the NodeInfoGETHandler.
func (m *Module) NodeInfoWellKnownGETHandler(c *gin.Context) {
l := m.log.WithFields(logrus.Fields{
"func": "NodeInfoWellKnownGETHandler",
"user-agent": c.Request.UserAgent(),
})

niRel, err := m.processor.GetNodeInfoRel(c.Request)
if err != nil {
l.Debugf("error with get node info rel request: %s", err)
c.JSON(err.Code(), err.Safe())
return
}

c.JSON(http.StatusOK, niRel)
}
2 changes: 1 addition & 1 deletion internal/api/security/extraheaders.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import "github.com/gin-gonic/gin"

// ExtraHeaders adds any additional required headers to the response
func (m *Module) ExtraHeaders(c *gin.Context) {
c.Header("Server", "Mastodon")
c.Header("Server", "gotosocial")
}
3 changes: 3 additions & 0 deletions internal/cliactions/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/api/client/status"
"github.com/superseriousbusiness/gotosocial/internal/api/client/streaming"
"github.com/superseriousbusiness/gotosocial/internal/api/client/timeline"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/nodeinfo"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/user"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/webfinger"
"github.com/superseriousbusiness/gotosocial/internal/api/security"
Expand Down Expand Up @@ -124,6 +125,7 @@ var Start cliactions.GTSAction = func(ctx context.Context, c *config.Config, log
appsModule := app.New(c, processor, log)
followRequestsModule := followrequest.New(c, processor, log)
webfingerModule := webfinger.New(c, processor, log)
nodeInfoModule := nodeinfo.New(c, processor, log)
webBaseModule := web.New(c, processor, log)
usersModule := user.New(c, processor, log)
timelineModule := timeline.New(c, processor, log)
Expand Down Expand Up @@ -155,6 +157,7 @@ var Start cliactions.GTSAction = func(ctx context.Context, c *config.Config, log
adminModule,
statusModule,
webfingerModule,
nodeInfoModule,
usersModule,
timelineModule,
notificationModule,
Expand Down
3 changes: 3 additions & 0 deletions internal/cliactions/testrig/testrig.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/api/client/status"
"github.com/superseriousbusiness/gotosocial/internal/api/client/streaming"
"github.com/superseriousbusiness/gotosocial/internal/api/client/timeline"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/nodeinfo"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/user"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/webfinger"
"github.com/superseriousbusiness/gotosocial/internal/api/security"
Expand Down Expand Up @@ -70,6 +71,7 @@ var Start cliactions.GTSAction = func(ctx context.Context, _ *config.Config, log
appsModule := app.New(c, processor, log)
followRequestsModule := followrequest.New(c, processor, log)
webfingerModule := webfinger.New(c, processor, log)
nodeInfoModule := nodeinfo.New(c, processor, log)
webBaseModule := web.New(c, processor, log)
usersModule := user.New(c, processor, log)
timelineModule := timeline.New(c, processor, log)
Expand Down Expand Up @@ -101,6 +103,7 @@ var Start cliactions.GTSAction = func(ctx context.Context, _ *config.Config, log
adminModule,
statusModule,
webfingerModule,
nodeInfoModule,
usersModule,
timelineModule,
notificationModule,
Expand Down
5 changes: 4 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ type Config struct {

/*
Not parsed from .yaml configuration file.
For short running commands (admin CLI tools etc).
*/
AccountCLIFlags map[string]string
SoftwareVersion string
}

// FromFile returns a new config from a file, or an error if something goes amiss.
Expand Down Expand Up @@ -252,6 +252,8 @@ func (c *Config) ParseCLIFlags(f KeyedFlags) error {
c.LetsEncryptConfig.EmailAddress = f.String(fn.LetsEncryptEmailAddress)
}

c.SoftwareVersion = GetDefaults().SoftwareVersion

// command-specific flags

// admin account CLI flags
Expand Down Expand Up @@ -323,6 +325,7 @@ type Defaults struct {
ConfigPath string
Host string
Protocol string
SoftwareVersion string

DbType string
DbAddress string
Expand Down
6 changes: 6 additions & 0 deletions internal/config/default.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package config

const softwareVersion = "0.1.0-SNAPSHOT"

// TestDefault returns a default config for testing
func TestDefault() *Config {
defaults := GetTestDefaults()
Expand All @@ -8,6 +10,7 @@ func TestDefault() *Config {
ApplicationName: defaults.ApplicationName,
Host: defaults.Host,
Protocol: defaults.Protocol,
SoftwareVersion: defaults.SoftwareVersion,
DBConfig: &DBConfig{
Type: defaults.DbType,
Address: defaults.DbAddress,
Expand Down Expand Up @@ -62,6 +65,7 @@ func Default() *Config {
ApplicationName: defaults.ApplicationName,
Host: defaults.Host,
Protocol: defaults.Protocol,
SoftwareVersion: defaults.SoftwareVersion,
DBConfig: &DBConfig{
Type: defaults.DbType,
Address: defaults.DbAddress,
Expand Down Expand Up @@ -117,6 +121,7 @@ func GetDefaults() Defaults {
ConfigPath: "",
Host: "",
Protocol: "https",
SoftwareVersion: softwareVersion,

DbType: "postgres",
DbAddress: "localhost",
Expand Down Expand Up @@ -163,6 +168,7 @@ func GetTestDefaults() Defaults {
ConfigPath: "",
Host: "localhost:8080",
Protocol: "http",
SoftwareVersion: softwareVersion,

DbType: "postgres",
DbAddress: "localhost",
Expand Down
Loading