mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 22:42:24 -05:00 
			
		
		
		
	Webfinger + Small fixes (#20)
This commit is contained in:
		
					parent
					
						
							
								41915ab371
							
						
					
				
			
			
				commit
				
					
						dc338dc881
					
				
			
		
					 16 changed files with 246 additions and 40 deletions
				
			
		|  | @ -77,7 +77,7 @@ | |||
|     * [x] /api/v1/statuses/:id/favourited_by GET            (See who has faved a status) | ||||
|     * [x] /api/v1/statuses/:id/favourite POST               (Fave a status) | ||||
|     * [x] /api/v1/statuses/:id/unfavourite POST             (Unfave a status) | ||||
|     * [ ] /api/v1/statuses/:id/reblog POST                  (Reblog a status) | ||||
|     * [x] /api/v1/statuses/:id/reblog POST                  (Reblog a status) | ||||
|     * [ ] /api/v1/statuses/:id/unreblog POST                (Undo a reblog) | ||||
|     * [ ] /api/v1/statuses/:id/bookmark POST                (Bookmark a status) | ||||
|     * [ ] /api/v1/statuses/:id/unbookmark POST              (Undo a bookmark) | ||||
|  | @ -133,7 +133,7 @@ | |||
|   * [ ] Search | ||||
|     * [ ] /api/v2/search GET                                (Get search query results) | ||||
|   * [ ] Instance | ||||
|     * [ ] /api/v1/instance GET                              (Get instance information) | ||||
|     * [x] /api/v1/instance GET                              (Get instance information) | ||||
|     * [ ] /api/v1/instance PATCH                            (Update instance information) | ||||
|     * [ ] /api/v1/instance/peers GET                        (Get list of federated servers) | ||||
|     * [ ] /api/v1/instance/activity GET                     (Instance activity over the last 3 months, binned weekly.) | ||||
|  | @ -169,7 +169,8 @@ | |||
|   * [ ] Oembed | ||||
|     * [ ] /api/oembed GET                                   (Get oembed metadata for a status URL) | ||||
| * [ ] Server-To-Server (Federation protocol) | ||||
|   * [ ] Mechanism to trigger side effects from client AP | ||||
|   * [x] Mechanism to trigger side effects from client AP | ||||
|   * [x] Webfinger account lookups | ||||
|   * [ ] Federation modes | ||||
|     * [ ] 'Slow' federation | ||||
|       * [ ] Reputation scoring system for instances | ||||
|  |  | |||
							
								
								
									
										39
									
								
								internal/api/model/webfinger.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								internal/api/model/webfinger.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | |||
| package model | ||||
| 
 | ||||
| /* | ||||
|    GoToSocial | ||||
|    Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org | ||||
| 
 | ||||
|    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/>. | ||||
| */ | ||||
| 
 | ||||
| // WebfingerAccountResponse represents the response to a webfinger request for an 'acct' resource. | ||||
| // For example, it would be returned from https://example.org/.well-known/webfinger?resource=acct:some_username@example.org | ||||
| // | ||||
| // See https://webfinger.net/ | ||||
| type WebfingerAccountResponse struct { | ||||
| 	Subject string          `json:"subject"` | ||||
| 	Aliases []string        `json:"aliases"` | ||||
| 	Links   []WebfingerLink `json:"links"` | ||||
| } | ||||
| 
 | ||||
| // WebfingerLink represents one 'link' in a slice of webfinger links returned from a lookup request. | ||||
| // | ||||
| // See https://webfinger.net/ | ||||
| type WebfingerLink struct { | ||||
| 	Rel      string `json:"rel"` | ||||
| 	Type     string `json:"type,omitempty"` | ||||
| 	Href     string `json:"href,omitempty"` | ||||
| 	Template string `json:"template,omitempty"` | ||||
| } | ||||
							
								
								
									
										56
									
								
								internal/api/s2s/webfinger/webfinger.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								internal/api/s2s/webfinger/webfinger.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| /* | ||||
|    GoToSocial | ||||
|    Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org | ||||
| 
 | ||||
|    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 webfinger | ||||
| 
 | ||||
| import ( | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"github.com/sirupsen/logrus" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/api" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/config" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/message" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/router" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// The base path for serving webfinger lookup requests | ||||
| 	WebfingerBasePath = ".well-known/webfinger" | ||||
| ) | ||||
| 
 | ||||
| // Module implements the FederationModule interface | ||||
| type Module struct { | ||||
| 	config    *config.Config | ||||
| 	processor message.Processor | ||||
| 	log       *logrus.Logger | ||||
| } | ||||
| 
 | ||||
| // New returns a new webfinger module | ||||
| func New(config *config.Config, processor message.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, WebfingerBasePath, m.WebfingerGETRequest) | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										68
									
								
								internal/api/s2s/webfinger/webfingerget.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								internal/api/s2s/webfinger/webfingerget.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | |||
| /* | ||||
|    GoToSocial | ||||
|    Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org | ||||
| 
 | ||||
|    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 webfinger | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/gin-gonic/gin" | ||||
| ) | ||||
| 
 | ||||
| // WebfingerGETRequest handles requests to, for example, https://example.org/.well-known/webfinger?resource=acct:some_user@example.org | ||||
| func (m *Module) WebfingerGETRequest(c *gin.Context) { | ||||
| 
 | ||||
| 	q, set := c.GetQuery("resource") | ||||
| 	if !set || q == "" { | ||||
| 		c.JSON(http.StatusBadRequest, gin.H{"error": "no 'resource' in request query"}) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	withAcct := strings.Split(q, "acct:") | ||||
| 	if len(withAcct) != 2 { | ||||
| 		c.JSON(http.StatusBadRequest, gin.H{"error": "bad request"}) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	usernameDomain := strings.Split(withAcct[1], "@") | ||||
| 	if len(usernameDomain) != 2 { | ||||
| 		c.JSON(http.StatusBadRequest, gin.H{"error": "bad request"}) | ||||
| 		return | ||||
| 	} | ||||
| 	username := strings.ToLower(usernameDomain[0]) | ||||
| 	domain := strings.ToLower(usernameDomain[1]) | ||||
| 	if username == "" || domain == "" { | ||||
| 		c.JSON(http.StatusBadRequest, gin.H{"error": "bad request"}) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if domain != m.config.Host { | ||||
| 		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("domain %s does not belong to this instance", domain)}) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	resp, err := m.processor.GetWebfingerAccount(username, c.Request) | ||||
| 	if err != nil { | ||||
| 		c.JSON(err.Code(), gin.H{"error": err.Safe()}) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	c.JSON(http.StatusOK, resp) | ||||
| } | ||||
|  | @ -344,8 +344,8 @@ func (ps *postgresService) CreateInstanceAccount() error { | |||
| func (ps *postgresService) CreateInstanceInstance() error { | ||||
| 	i := >smodel.Instance{ | ||||
| 		Domain: ps.config.Host, | ||||
| 		Title: ps.config.Host, | ||||
| 		URI: fmt.Sprintf("%s://%s", ps.config.Protocol, ps.config.Host), | ||||
| 		Title:  ps.config.Host, | ||||
| 		URI:    fmt.Sprintf("%s://%s", ps.config.Protocol, ps.config.Host), | ||||
| 	} | ||||
| 	inserted, err := ps.conn.Model(i).Where("domain = ?", ps.config.Host).SelectOrInsert() | ||||
| 	if err != nil { | ||||
|  | @ -354,7 +354,7 @@ func (ps *postgresService) CreateInstanceInstance() error { | |||
| 	if inserted { | ||||
| 		ps.log.Infof("created instance instance %s with id %s", ps.config.Host, i.ID) | ||||
| 	} else { | ||||
| 		ps.log.Infof("instance instance %s already exists with id %s",  ps.config.Host, i.ID) | ||||
| 		ps.log.Infof("instance instance %s already exists with id %s", ps.config.Host, i.ID) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
|  | @ -112,6 +112,9 @@ func getPublicKeyFromResponse(c context.Context, b []byte, keyID *url.URL) (voca | |||
| // Also note that this function *does not* dereference the remote account that the signature key is associated with. | ||||
| // Other functions should use the returned URL to dereference the remote account, if required. | ||||
| func (f *federator) AuthenticateFederatedRequest(username string, r *http.Request) (*url.URL, error) { | ||||
| 	// set this extra field for signature validation | ||||
| 	r.Header.Set("host", f.config.Host) | ||||
| 
 | ||||
| 	verifier, err := httpsig.NewVerifier(r) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("could not create http sig verifier: %s", err) | ||||
|  | @ -208,7 +211,11 @@ func (f *federator) DereferenceRemoteAccount(username string, remoteAccountID *u | |||
| 		} | ||||
| 		return p, nil | ||||
| 	case string(gtsmodel.ActivityStreamsApplication): | ||||
| 		// TODO: convert application into person | ||||
| 		p, ok := t.(vocab.ActivityStreamsApplication) | ||||
| 		if !ok { | ||||
| 			return nil, errors.New("error resolving type as activitystreams application") | ||||
| 		} | ||||
| 		return p, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, fmt.Errorf("type name %s not supported", t.GetTypeName()) | ||||
|  |  | |||
|  | @ -37,6 +37,8 @@ import ( | |||
| 	"github.com/superseriousbusiness/gotosocial/internal/api/client/instance" | ||||
| 	mediaModule "github.com/superseriousbusiness/gotosocial/internal/api/client/media" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/api/client/status" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/api/s2s/user" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/api/s2s/webfinger" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/api/security" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/config" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/db" | ||||
|  | @ -109,6 +111,8 @@ var Run action.GTSAction = func(ctx context.Context, c *config.Config, log *logr | |||
| 	accountModule := account.New(c, processor, log) | ||||
| 	instanceModule := instance.New(c, processor, log) | ||||
| 	appsModule := app.New(c, processor, log) | ||||
| 	webfingerModule := webfinger.New(c, processor, log) | ||||
| 	usersModule := user.New(c, processor, log) | ||||
| 	mm := mediaModule.New(c, processor, log) | ||||
| 	fileServerModule := fileserver.New(c, processor, log) | ||||
| 	adminModule := admin.New(c, processor, log) | ||||
|  | @ -128,6 +132,8 @@ var Run action.GTSAction = func(ctx context.Context, c *config.Config, log *logr | |||
| 		fileServerModule, | ||||
| 		adminModule, | ||||
| 		statusModule, | ||||
| 		webfingerModule, | ||||
| 		usersModule, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, m := range apis { | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ type Instance struct { | |||
| 	// When was this instance created in the db? | ||||
| 	CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"` | ||||
| 	// When was this instance last updated in the db? | ||||
| 	UpdatedAt   time.Time `pg:"type:timestamp,notnull,default:now()"` | ||||
| 	UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"` | ||||
| 	// When was this instance suspended, if at all? | ||||
| 	SuspendedAt time.Time | ||||
| 	// ID of any existing domain block for this instance in the database | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ import ( | |||
| 	"net/http" | ||||
| 
 | ||||
| 	"github.com/go-fed/activity/streams" | ||||
| 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/db" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||||
| ) | ||||
|  | @ -100,3 +101,32 @@ func (p *processor) GetFediUser(requestedUsername string, request *http.Request) | |||
| 
 | ||||
| 	return data, nil | ||||
| } | ||||
| 
 | ||||
| func (p *processor) GetWebfingerAccount(requestedUsername string, request *http.Request) (*apimodel.WebfingerAccountResponse, ErrorWithCode) { | ||||
| 	// get the account the request is referring to | ||||
| 	requestedAccount := >smodel.Account{} | ||||
| 	if err := p.db.GetLocalAccountByUsername(requestedUsername, requestedAccount); err != nil { | ||||
| 		return nil, NewErrorNotFound(fmt.Errorf("database error getting account with username %s: %s", requestedUsername, err)) | ||||
| 	} | ||||
| 
 | ||||
| 	// return the webfinger representation | ||||
| 	return &apimodel.WebfingerAccountResponse{ | ||||
| 		Subject: fmt.Sprintf("acct:%s@%s", requestedAccount.Username, p.config.Host), | ||||
| 		Aliases: []string{ | ||||
| 			requestedAccount.URI, | ||||
| 			requestedAccount.URL, | ||||
| 		}, | ||||
| 		Links: []apimodel.WebfingerLink{ | ||||
| 			{ | ||||
| 				Rel:  "http://webfinger.net/rel/profile-page", | ||||
| 				Type: "text/html", | ||||
| 				Href: requestedAccount.URL, | ||||
| 			}, | ||||
| 			{ | ||||
| 				Rel:  "self", | ||||
| 				Type: "application/activity+json", | ||||
| 				Href: requestedAccount.URI, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
|  |  | |||
|  | @ -18,5 +18,5 @@ func (p *processor) InstanceGet(domain string) (*apimodel.Instance, ErrorWithCod | |||
| 		return nil, NewErrorInternalError(fmt.Errorf("error converting instance to api representation: %s", err)) | ||||
| 	} | ||||
| 
 | ||||
| 	return  ai, nil | ||||
| 	return ai, nil | ||||
| } | ||||
|  |  | |||
|  | @ -108,6 +108,9 @@ type Processor interface { | |||
| 	// GetFediUser handles the getting of a fedi/activitypub representation of a user/account, performing appropriate authentication | ||||
| 	// before returning a JSON serializable interface to the caller. | ||||
| 	GetFediUser(requestedUsername string, request *http.Request) (interface{}, ErrorWithCode) | ||||
| 
 | ||||
| 	// GetWebfingerAccount handles the GET for a webfinger resource. Most commonly, it will be used for returning account lookups. | ||||
| 	GetWebfingerAccount(requestedUsername string, request *http.Request) (*apimodel.WebfingerAccountResponse, ErrorWithCode) | ||||
| } | ||||
| 
 | ||||
| // processor just implements the Processor interface | ||||
|  |  | |||
|  | @ -25,6 +25,7 @@ import ( | |||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/gin-contrib/sessions" | ||||
| 	"github.com/gin-contrib/sessions/memstore" | ||||
|  | @ -140,7 +141,13 @@ func New(config *config.Config, logger *logrus.Logger) (Router, error) { | |||
| 	engine.LoadHTMLGlob(tmPath) | ||||
| 
 | ||||
| 	// create the actual http server here | ||||
| 	var s *http.Server | ||||
| 	s := &http.Server{ | ||||
| 		Handler:           engine, | ||||
| 		ReadTimeout:       1 * time.Second, | ||||
| 		WriteTimeout:      1 * time.Second, | ||||
| 		IdleTimeout:       30 * time.Second, | ||||
| 		ReadHeaderTimeout: 2 * time.Second, | ||||
| 	} | ||||
| 	var m *autocert.Manager | ||||
| 
 | ||||
| 	// We need to spawn the underlying server slightly differently depending on whether lets encrypt is enabled or not. | ||||
|  | @ -154,17 +161,11 @@ func New(config *config.Config, logger *logrus.Logger) (Router, error) { | |||
| 			Email:      config.LetsEncryptConfig.EmailAddress, | ||||
| 		} | ||||
| 		// and create an HTTPS server | ||||
| 		s = &http.Server{ | ||||
| 			Addr:      ":https", | ||||
| 			TLSConfig: m.TLSConfig(), | ||||
| 			Handler:   engine, | ||||
| 		} | ||||
| 		s.Addr = ":https" | ||||
| 		s.TLSConfig = m.TLSConfig() | ||||
| 	} else { | ||||
| 		// le is NOT enabled, so just serve bare requests on port 8080 | ||||
| 		s = &http.Server{ | ||||
| 			Addr:    ":8080", | ||||
| 			Handler: engine, | ||||
| 		} | ||||
| 		s.Addr = ":8080" | ||||
| 	} | ||||
| 
 | ||||
| 	return &router{ | ||||
|  |  | |||
|  | @ -54,8 +54,8 @@ func NewController(config *config.Config, clock pub.Clock, client pub.HttpClient | |||
| func (c *controller) NewTransport(pubKeyID string, privkey crypto.PrivateKey) (pub.Transport, error) { | ||||
| 	prefs := []httpsig.Algorithm{httpsig.RSA_SHA256, httpsig.RSA_SHA512} | ||||
| 	digestAlgo := httpsig.DigestSha256 | ||||
| 	getHeaders := []string{"(request-target)", "date"} | ||||
| 	postHeaders := []string{"(request-target)", "date", "digest"} | ||||
| 	getHeaders := []string{"(request-target)", "date", "accept"} | ||||
| 	postHeaders := []string{"(request-target)", "date", "accept", "digest"} | ||||
| 
 | ||||
| 	getSigner, _, err := httpsig.NewSigner(prefs, digestAlgo, getHeaders, httpsig.Signature) | ||||
| 	if err != nil { | ||||
|  |  | |||
|  | @ -119,31 +119,26 @@ func (c *converter) ASRepresentationToAccount(accountable Accountable) (*gtsmode | |||
| 	acct.URL = url.String() | ||||
| 
 | ||||
| 	// InboxURI | ||||
| 	if accountable.GetActivityStreamsInbox() == nil || accountable.GetActivityStreamsInbox().GetIRI() == nil { | ||||
| 		return nil, fmt.Errorf("person with id %s had no inbox uri", uri.String()) | ||||
| 	if accountable.GetActivityStreamsInbox() != nil || accountable.GetActivityStreamsInbox().GetIRI() != nil { | ||||
| 		acct.InboxURI = accountable.GetActivityStreamsInbox().GetIRI().String() | ||||
| 	} | ||||
| 	acct.InboxURI = accountable.GetActivityStreamsInbox().GetIRI().String() | ||||
| 
 | ||||
| 	// OutboxURI | ||||
| 	if accountable.GetActivityStreamsOutbox() == nil || accountable.GetActivityStreamsOutbox().GetIRI() == nil { | ||||
| 		return nil, fmt.Errorf("person with id %s had no outbox uri", uri.String()) | ||||
| 	if accountable.GetActivityStreamsOutbox() != nil && accountable.GetActivityStreamsOutbox().GetIRI() != nil { | ||||
| 		acct.OutboxURI = accountable.GetActivityStreamsOutbox().GetIRI().String() | ||||
| 	} | ||||
| 	acct.OutboxURI = accountable.GetActivityStreamsOutbox().GetIRI().String() | ||||
| 
 | ||||
| 	// FollowingURI | ||||
| 	if accountable.GetActivityStreamsFollowing() == nil || accountable.GetActivityStreamsFollowing().GetIRI() == nil { | ||||
| 		return nil, fmt.Errorf("person with id %s had no following uri", uri.String()) | ||||
| 	if accountable.GetActivityStreamsFollowing() != nil && accountable.GetActivityStreamsFollowing().GetIRI() != nil { | ||||
| 		acct.FollowingURI = accountable.GetActivityStreamsFollowing().GetIRI().String() | ||||
| 	} | ||||
| 	acct.FollowingURI = accountable.GetActivityStreamsFollowing().GetIRI().String() | ||||
| 
 | ||||
| 	// FollowersURI | ||||
| 	if accountable.GetActivityStreamsFollowers() == nil || accountable.GetActivityStreamsFollowers().GetIRI() == nil { | ||||
| 		return nil, fmt.Errorf("person with id %s had no followers uri", uri.String()) | ||||
| 	if accountable.GetActivityStreamsFollowers() != nil && accountable.GetActivityStreamsFollowers().GetIRI() != nil { | ||||
| 		acct.FollowersURI = accountable.GetActivityStreamsFollowers().GetIRI().String() | ||||
| 	} | ||||
| 	acct.FollowersURI = accountable.GetActivityStreamsFollowers().GetIRI().String() | ||||
| 
 | ||||
| 	// FeaturedURI | ||||
| 	// very much optional | ||||
| 	if accountable.GetTootFeatured() != nil && accountable.GetTootFeatured().GetIRI() != nil { | ||||
| 		acct.FeaturedCollectionURI = accountable.GetTootFeatured().GetIRI().String() | ||||
| 	} | ||||
|  |  | |||
|  | @ -554,11 +554,11 @@ func (c *converter) VisToMasto(m gtsmodel.Visibility) model.Visibility { | |||
| 
 | ||||
| func (c *converter) InstanceToMasto(i *gtsmodel.Instance) (*model.Instance, error) { | ||||
| 	mi := &model.Instance{ | ||||
| 		URI: i.URI, | ||||
| 		Title: i.Title, | ||||
| 		Description: i.Description, | ||||
| 		URI:              i.URI, | ||||
| 		Title:            i.Title, | ||||
| 		Description:      i.Description, | ||||
| 		ShortDescription: i.ShortDescription, | ||||
| 		Email: i.ContactEmail, | ||||
| 		Email:            i.ContactEmail, | ||||
| 	} | ||||
| 
 | ||||
| 	if i.Domain == c.config.Host { | ||||
|  |  | |||
|  | @ -46,7 +46,7 @@ const ( | |||
| 	// FeaturedPath represents the webfinger featured location | ||||
| 	FeaturedPath = "featured" | ||||
| 	// PublicKeyPath is for serving an account's public key | ||||
| 	PublicKeyPath = "publickey" | ||||
| 	PublicKeyPath = "main-key" | ||||
| ) | ||||
| 
 | ||||
| // APContextKey is a type used specifically for settings values on contexts within go-fed AP request chains | ||||
|  | @ -113,7 +113,7 @@ func GenerateURIsForAccount(username string, protocol string, host string) *User | |||
| 	followingURI := fmt.Sprintf("%s/%s", userURI, FollowingPath) | ||||
| 	likedURI := fmt.Sprintf("%s/%s", userURI, LikedPath) | ||||
| 	collectionURI := fmt.Sprintf("%s/%s/%s", userURI, CollectionsPath, FeaturedPath) | ||||
| 	publicKeyURI := fmt.Sprintf("%s/%s", userURI, PublicKeyPath) | ||||
| 	publicKeyURI := fmt.Sprintf("%s#%s", userURI, PublicKeyPath) | ||||
| 
 | ||||
| 	return &UserURIs{ | ||||
| 		HostURL:     hostURL, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue