mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 02:52:26 -05:00 
			
		
		
		
	start work on AP inbox post
This commit is contained in:
		
					parent
					
						
							
								742f985d5b
							
						
					
				
			
			
				commit
				
					
						d09a8a1f05
					
				
			
		
					 12 changed files with 207 additions and 22 deletions
				
			
		
							
								
								
									
										2
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
										
									
									
									
								
							|  | @ -7,7 +7,7 @@ require ( | ||||||
| 	github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect | 	github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect | ||||||
| 	github.com/gin-contrib/sessions v0.0.3 | 	github.com/gin-contrib/sessions v0.0.3 | ||||||
| 	github.com/gin-gonic/gin v1.6.3 | 	github.com/gin-gonic/gin v1.6.3 | ||||||
| 	github.com/go-fed/activity v1.0.0 | 	github.com/go-fed/activity v1.0.1-0.20210426194615-e0de0863dcc1 | ||||||
| 	github.com/go-fed/httpsig v0.1.1-0.20190914113940-c2de3672e5b5 | 	github.com/go-fed/httpsig v0.1.1-0.20190914113940-c2de3672e5b5 | ||||||
| 	github.com/go-pg/pg/extra/pgdebug v0.2.0 | 	github.com/go-pg/pg/extra/pgdebug v0.2.0 | ||||||
| 	github.com/go-pg/pg/v10 v10.8.0 | 	github.com/go-pg/pg/v10 v10.8.0 | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
										
									
									
									
								
							|  | @ -59,8 +59,8 @@ github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0 | ||||||
| github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= | github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= | ||||||
| github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4= | github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4= | ||||||
| github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= | github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= | ||||||
| github.com/go-fed/activity v1.0.0 h1:j7w3auHZnVCjUcgA1mE+UqSOjFBhvW2Z2res3vNol+o= | github.com/go-fed/activity v1.0.1-0.20210426194615-e0de0863dcc1 h1:go9MogQW0eTLwdOs/ZfNCGpwUkVcr7IMUbI3u8wYQxw= | ||||||
| github.com/go-fed/activity v1.0.0/go.mod h1:v4QoPaAzjWZ8zN2VFVGL5ep9C02mst0hQYHUpQwso4Q= | github.com/go-fed/activity v1.0.1-0.20210426194615-e0de0863dcc1/go.mod h1:v4QoPaAzjWZ8zN2VFVGL5ep9C02mst0hQYHUpQwso4Q= | ||||||
| github.com/go-fed/httpsig v0.1.1-0.20190914113940-c2de3672e5b5 h1:WLvFZqoXnuVTBKA6U/1FnEHNQ0Rq0QM0rGhY8Tx6R1g= | github.com/go-fed/httpsig v0.1.1-0.20190914113940-c2de3672e5b5 h1:WLvFZqoXnuVTBKA6U/1FnEHNQ0Rq0QM0rGhY8Tx6R1g= | ||||||
| github.com/go-fed/httpsig v0.1.1-0.20190914113940-c2de3672e5b5/go.mod h1:T56HUNYZUQ1AGUzhAYPugZfp36sKApVnGBgKlIY+aIE= | github.com/go-fed/httpsig v0.1.1-0.20190914113940-c2de3672e5b5/go.mod h1:T56HUNYZUQ1AGUzhAYPugZfp36sKApVnGBgKlIY+aIE= | ||||||
| github.com/go-pg/pg/extra/pgdebug v0.2.0 h1:t62UhMiV6KYAxSWojwIJiyX06TdepkzCeIzdeb00184= | github.com/go-pg/pg/extra/pgdebug v0.2.0 h1:t62UhMiV6KYAxSWojwIJiyX06TdepkzCeIzdeb00184= | ||||||
|  |  | ||||||
							
								
								
									
										56
									
								
								internal/api/s2s/user/inboxpost.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								internal/api/s2s/user/inboxpost.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 user | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"net/http" | ||||||
|  | 
 | ||||||
|  | 	"github.com/gin-gonic/gin" | ||||||
|  | 	"github.com/sirupsen/logrus" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/message" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func (m *Module) InboxPOSTHandler(c *gin.Context) { | ||||||
|  | 	l := m.log.WithFields(logrus.Fields{ | ||||||
|  | 		"func": "InboxPOSTHandler", | ||||||
|  | 		"url":  c.Request.RequestURI, | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	requestedUsername := c.Param(UsernameKey) | ||||||
|  | 	if requestedUsername == "" { | ||||||
|  | 		c.JSON(http.StatusBadRequest, gin.H{"error": "no username specified in request"}) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	posted, err := m.processor.InboxPost(c.Request.Context(), c.Writer, c.Request) | ||||||
|  | 	if err != nil { | ||||||
|  | 		if withCode, ok := err.(message.ErrorWithCode); ok { | ||||||
|  | 			l.Debug(withCode.Error()) | ||||||
|  | 			c.JSON(withCode.Code(), withCode.Safe()) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		l.Debug(err) | ||||||
|  | 		c.JSON(http.StatusBadRequest, gin.H{"error": "unable to process request"}) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !posted { | ||||||
|  | 		c.JSON(http.StatusBadRequest, gin.H{"error": "unable to process request"}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -38,6 +38,7 @@ const ( | ||||||
| 	// Use this anywhere you need to know the username of the user being queried. | 	// Use this anywhere you need to know the username of the user being queried. | ||||||
| 	// Eg https://example.org/users/:username | 	// Eg https://example.org/users/:username | ||||||
| 	UsersBasePathWithUsername = UsersBasePath + "/:" + UsernameKey | 	UsersBasePathWithUsername = UsersBasePath + "/:" + UsernameKey | ||||||
|  | 	UsersInboxPath            = UsersBasePathWithUsername + "/" + util.InboxPath | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // ActivityPubAcceptHeaders represents the Accept headers mentioned here: | // ActivityPubAcceptHeaders represents the Accept headers mentioned here: | ||||||
|  | @ -66,5 +67,6 @@ func New(config *config.Config, processor message.Processor, log *logrus.Logger) | ||||||
| // Route satisfies the RESTAPIModule interface | // Route satisfies the RESTAPIModule interface | ||||||
| func (m *Module) Route(s router.Router) error { | func (m *Module) Route(s router.Router) error { | ||||||
| 	s.AttachHandler(http.MethodGet, UsersBasePathWithUsername, m.UsersGETHandler) | 	s.AttachHandler(http.MethodGet, UsersBasePathWithUsername, m.UsersGETHandler) | ||||||
|  | 	s.AttachHandler(http.MethodPost, UsersInboxPath, m.InboxPOSTHandler) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -104,6 +104,13 @@ func (f *federatingDB) Unlock(c context.Context, id *url.URL) error { | ||||||
| // | // | ||||||
| // The library makes this call only after acquiring a lock first. | // The library makes this call only after acquiring a lock first. | ||||||
| func (f *federatingDB) InboxContains(c context.Context, inbox, id *url.URL) (contains bool, err error) { | func (f *federatingDB) InboxContains(c context.Context, inbox, id *url.URL) (contains bool, err error) { | ||||||
|  | 	l := f.log.WithFields( | ||||||
|  | 		logrus.Fields{ | ||||||
|  | 			"func": "InboxContains", | ||||||
|  | 			"id": id.String(), | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | 	l.Debug("entering INBOXCONTAINS function") | ||||||
| 
 | 
 | ||||||
| 	if !util.IsInboxPath(inbox) { | 	if !util.IsInboxPath(inbox) { | ||||||
| 		return false, fmt.Errorf("%s is not an inbox URI", inbox.String()) | 		return false, fmt.Errorf("%s is not an inbox URI", inbox.String()) | ||||||
|  | @ -151,6 +158,14 @@ func (f *federatingDB) SetInbox(c context.Context, inbox vocab.ActivityStreamsOr | ||||||
| // the database has an entry for the IRI. | // the database has an entry for the IRI. | ||||||
| // The library makes this call only after acquiring a lock first. | // The library makes this call only after acquiring a lock first. | ||||||
| func (f *federatingDB) Owns(c context.Context, id *url.URL) (bool, error) { | func (f *federatingDB) Owns(c context.Context, id *url.URL) (bool, error) { | ||||||
|  | 	l := f.log.WithFields( | ||||||
|  | 		logrus.Fields{ | ||||||
|  | 			"func": "Owns", | ||||||
|  | 			"id": id.String(), | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | 	l.Debug("entering OWNS function") | ||||||
|  | 
 | ||||||
| 	// if the id host isn't this instance host, we don't own this IRI | 	// if the id host isn't this instance host, we don't own this IRI | ||||||
| 	if id.Host != f.config.Host { | 	if id.Host != f.config.Host { | ||||||
| 		return false, nil | 		return false, nil | ||||||
|  | @ -199,6 +214,14 @@ func (f *federatingDB) Owns(c context.Context, id *url.URL) (bool, error) { | ||||||
| // | // | ||||||
| // The library makes this call only after acquiring a lock first. | // The library makes this call only after acquiring a lock first. | ||||||
| func (f *federatingDB) ActorForOutbox(c context.Context, outboxIRI *url.URL) (actorIRI *url.URL, err error) { | func (f *federatingDB) ActorForOutbox(c context.Context, outboxIRI *url.URL) (actorIRI *url.URL, err error) { | ||||||
|  | 	l := f.log.WithFields( | ||||||
|  | 		logrus.Fields{ | ||||||
|  | 			"func": "ActorForOutbox", | ||||||
|  | 			"inboxIRI": outboxIRI.String(), | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | 	l.Debug("entering ACTORFOROUTBOX function") | ||||||
|  | 
 | ||||||
| 	if !util.IsOutboxPath(outboxIRI) { | 	if !util.IsOutboxPath(outboxIRI) { | ||||||
| 		return nil, fmt.Errorf("%s is not an outbox URI", outboxIRI.String()) | 		return nil, fmt.Errorf("%s is not an outbox URI", outboxIRI.String()) | ||||||
| 	} | 	} | ||||||
|  | @ -216,6 +239,14 @@ func (f *federatingDB) ActorForOutbox(c context.Context, outboxIRI *url.URL) (ac | ||||||
| // | // | ||||||
| // The library makes this call only after acquiring a lock first. | // The library makes this call only after acquiring a lock first. | ||||||
| func (f *federatingDB) ActorForInbox(c context.Context, inboxIRI *url.URL) (actorIRI *url.URL, err error) { | func (f *federatingDB) ActorForInbox(c context.Context, inboxIRI *url.URL) (actorIRI *url.URL, err error) { | ||||||
|  | 	l := f.log.WithFields( | ||||||
|  | 		logrus.Fields{ | ||||||
|  | 			"func": "ActorForInbox", | ||||||
|  | 			"inboxIRI": inboxIRI.String(), | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | 	l.Debug("entering ACTORFORINBOX function") | ||||||
|  | 
 | ||||||
| 	if !util.IsInboxPath(inboxIRI) { | 	if !util.IsInboxPath(inboxIRI) { | ||||||
| 		return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String()) | 		return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String()) | ||||||
| 	} | 	} | ||||||
|  | @ -234,6 +265,14 @@ func (f *federatingDB) ActorForInbox(c context.Context, inboxIRI *url.URL) (acto | ||||||
| // | // | ||||||
| // The library makes this call only after acquiring a lock first. | // The library makes this call only after acquiring a lock first. | ||||||
| func (f *federatingDB) OutboxForInbox(c context.Context, inboxIRI *url.URL) (outboxIRI *url.URL, err error) { | func (f *federatingDB) OutboxForInbox(c context.Context, inboxIRI *url.URL) (outboxIRI *url.URL, err error) { | ||||||
|  | 	l := f.log.WithFields( | ||||||
|  | 		logrus.Fields{ | ||||||
|  | 			"func": "OutboxForInbox", | ||||||
|  | 			"inboxIRI": inboxIRI.String(), | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | 	l.Debug("entering OUTBOXFORINBOX function") | ||||||
|  | 
 | ||||||
| 	if !util.IsInboxPath(inboxIRI) { | 	if !util.IsInboxPath(inboxIRI) { | ||||||
| 		return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String()) | 		return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String()) | ||||||
| 	} | 	} | ||||||
|  | @ -252,6 +291,14 @@ func (f *federatingDB) OutboxForInbox(c context.Context, inboxIRI *url.URL) (out | ||||||
| // | // | ||||||
| // The library makes this call only after acquiring a lock first. | // The library makes this call only after acquiring a lock first. | ||||||
| func (f *federatingDB) Exists(c context.Context, id *url.URL) (exists bool, err error) { | func (f *federatingDB) Exists(c context.Context, id *url.URL) (exists bool, err error) { | ||||||
|  | 	l := f.log.WithFields( | ||||||
|  | 		logrus.Fields{ | ||||||
|  | 			"func": "Exists", | ||||||
|  | 			"id": id.String(), | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | 	l.Debug("entering EXISTS function") | ||||||
|  | 
 | ||||||
| 	return false, nil | 	return false, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -259,6 +306,13 @@ func (f *federatingDB) Exists(c context.Context, id *url.URL) (exists bool, err | ||||||
| // | // | ||||||
| // The library makes this call only after acquiring a lock first. | // The library makes this call only after acquiring a lock first. | ||||||
| func (f *federatingDB) Get(c context.Context, id *url.URL) (value vocab.Type, err error) { | func (f *federatingDB) Get(c context.Context, id *url.URL) (value vocab.Type, err error) { | ||||||
|  | 	l := f.log.WithFields( | ||||||
|  | 		logrus.Fields{ | ||||||
|  | 			"func": "Get", | ||||||
|  | 			"id": id.String(), | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | 	l.Debug("entering GET function") | ||||||
| 	return nil, nil | 	return nil, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -275,6 +329,13 @@ func (f *federatingDB) Get(c context.Context, id *url.URL) (value vocab.Type, er | ||||||
| // Under certain conditions and network activities, Create may be called | // Under certain conditions and network activities, Create may be called | ||||||
| // multiple times for the same ActivityStreams object. | // multiple times for the same ActivityStreams object. | ||||||
| func (f *federatingDB) Create(c context.Context, asType vocab.Type) error { | func (f *federatingDB) Create(c context.Context, asType vocab.Type) error { | ||||||
|  | 	l := f.log.WithFields( | ||||||
|  | 		logrus.Fields{ | ||||||
|  | 			"func": "Create", | ||||||
|  | 			"asType": asType.GetTypeName(), | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | 	l.Debugf("received CREATE asType %+v", asType) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -288,6 +349,13 @@ func (f *federatingDB) Create(c context.Context, asType vocab.Type) error { | ||||||
| // | // | ||||||
| // The library makes this call only after acquiring a lock first. | // The library makes this call only after acquiring a lock first. | ||||||
| func (f *federatingDB) Update(c context.Context, asType vocab.Type) error { | func (f *federatingDB) Update(c context.Context, asType vocab.Type) error { | ||||||
|  | 	l := f.log.WithFields( | ||||||
|  | 		logrus.Fields{ | ||||||
|  | 			"func": "Update", | ||||||
|  | 			"asType": asType.GetTypeName(), | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | 	l.Debugf("received UPDATE asType %+v", asType) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -298,6 +366,13 @@ func (f *federatingDB) Update(c context.Context, asType vocab.Type) error { | ||||||
| // | // | ||||||
| // The library makes this call only after acquiring a lock first. | // The library makes this call only after acquiring a lock first. | ||||||
| func (f *federatingDB) Delete(c context.Context, id *url.URL) error { | func (f *federatingDB) Delete(c context.Context, id *url.URL) error { | ||||||
|  | 	l := f.log.WithFields( | ||||||
|  | 		logrus.Fields{ | ||||||
|  | 			"func": "Delete", | ||||||
|  | 			"id": id.String(), | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | 	l.Debugf("received DELETE id %s", id.String()) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -325,6 +400,14 @@ func (f *federatingDB) SetOutbox(c context.Context, outbox vocab.ActivityStreams | ||||||
| // The go-fed library will handle setting the 'id' property on the | // The go-fed library will handle setting the 'id' property on the | ||||||
| // activity or object provided with the value returned. | // activity or object provided with the value returned. | ||||||
| func (f *federatingDB) NewID(c context.Context, t vocab.Type) (id *url.URL, err error) { | func (f *federatingDB) NewID(c context.Context, t vocab.Type) (id *url.URL, err error) { | ||||||
|  | 
 | ||||||
|  | 	l := f.log.WithFields( | ||||||
|  | 		logrus.Fields{ | ||||||
|  | 			"func": "NewID", | ||||||
|  | 			"asType": t.GetTypeName(), | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | 	l.Debugf("received NEWID request for asType %+v", t) | ||||||
| 	return nil, nil | 	return nil, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -57,7 +57,7 @@ import ( | ||||||
| // authenticated must be true and error nil. The request will continue | // authenticated must be true and error nil. The request will continue | ||||||
| // to be processed. | // to be processed. | ||||||
| func (f *federator) AuthenticateGetInbox(ctx context.Context, w http.ResponseWriter, r *http.Request) (context.Context, bool, error) { | func (f *federator) AuthenticateGetInbox(ctx context.Context, w http.ResponseWriter, r *http.Request) (context.Context, bool, error) { | ||||||
| 	// IMPLEMENTATION NOTE: For GoToSocial, we serve outboxes and inboxes through | 	// IMPLEMENTATION NOTE: For GoToSocial, we serve GETS to outboxes and inboxes through | ||||||
| 	// the CLIENT API, not through the federation API, so we just do nothing here. | 	// the CLIENT API, not through the federation API, so we just do nothing here. | ||||||
| 	return nil, false, nil | 	return nil, false, nil | ||||||
| } | } | ||||||
|  | @ -82,7 +82,7 @@ func (f *federator) AuthenticateGetInbox(ctx context.Context, w http.ResponseWri | ||||||
| // authenticated must be true and error nil. The request will continue | // authenticated must be true and error nil. The request will continue | ||||||
| // to be processed. | // to be processed. | ||||||
| func (f *federator) AuthenticateGetOutbox(ctx context.Context, w http.ResponseWriter, r *http.Request) (context.Context, bool, error) { | func (f *federator) AuthenticateGetOutbox(ctx context.Context, w http.ResponseWriter, r *http.Request) (context.Context, bool, error) { | ||||||
| 	// IMPLEMENTATION NOTE: For GoToSocial, we serve outboxes and inboxes through | 	// IMPLEMENTATION NOTE: For GoToSocial, we serve GETS to outboxes and inboxes through | ||||||
| 	// the CLIENT API, not through the federation API, so we just do nothing here. | 	// the CLIENT API, not through the federation API, so we just do nothing here. | ||||||
| 	return nil, false, nil | 	return nil, false, nil | ||||||
| } | } | ||||||
|  | @ -96,7 +96,7 @@ func (f *federator) AuthenticateGetOutbox(ctx context.Context, w http.ResponseWr | ||||||
| // Always called, regardless whether the Federated Protocol or Social | // Always called, regardless whether the Federated Protocol or Social | ||||||
| // API is enabled. | // API is enabled. | ||||||
| func (f *federator) GetOutbox(ctx context.Context, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error) { | func (f *federator) GetOutbox(ctx context.Context, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error) { | ||||||
| 	// IMPLEMENTATION NOTE: For GoToSocial, we serve outboxes and inboxes through | 	// IMPLEMENTATION NOTE: For GoToSocial, we serve GETS to outboxes and inboxes through | ||||||
| 	// the CLIENT API, not through the federation API, so we just do nothing here. | 	// the CLIENT API, not through the federation API, so we just do nothing here. | ||||||
| 	return nil, nil | 	return nil, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -77,6 +77,13 @@ func (f *federatingActor) PostInbox(c context.Context, w http.ResponseWriter, r | ||||||
| 	return f.actor.PostInbox(c, w, r) | 	return f.actor.PostInbox(c, w, r) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // PostInboxScheme is similar to PostInbox, except clients are able to | ||||||
|  | // specify which protocol scheme to handle the incoming request and the | ||||||
|  | // data stored within the application (HTTP, HTTPS, etc). | ||||||
|  | func (f *federatingActor) PostInboxScheme(c context.Context, w http.ResponseWriter, r *http.Request, scheme string) (bool, error) { | ||||||
|  | 	return f.actor.PostInboxScheme(c, w, r, scheme) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // GetInbox returns true if the request was handled as an ActivityPub | // GetInbox returns true if the request was handled as an ActivityPub | ||||||
| // GET to an actor's inbox. If false, the request was not an ActivityPub | // GET to an actor's inbox. If false, the request was not an ActivityPub | ||||||
| // request and may still be handled by the caller in another way, such | // request and may still be handled by the caller in another way, such | ||||||
|  | @ -118,6 +125,13 @@ func (f *federatingActor) PostOutbox(c context.Context, w http.ResponseWriter, r | ||||||
| 	return f.actor.PostOutbox(c, w, r) | 	return f.actor.PostOutbox(c, w, r) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // PostOutboxScheme is similar to PostOutbox, except clients are able to | ||||||
|  | // specify which protocol scheme to handle the incoming request and the | ||||||
|  | // data stored within the application (HTTP, HTTPS, etc). | ||||||
|  | func (f *federatingActor) PostOutboxScheme(c context.Context, w http.ResponseWriter, r *http.Request, scheme string) (bool, error) { | ||||||
|  | 	return f.actor.PostOutboxScheme(c, w, r, scheme) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // GetOutbox returns true if the request was handled as an ActivityPub | // GetOutbox returns true if the request was handled as an ActivityPub | ||||||
| // GET to an actor's outbox. If false, the request was not an | // GET to an actor's outbox. If false, the request was not an | ||||||
| // ActivityPub request. | // ActivityPub request. | ||||||
|  |  | ||||||
|  | @ -72,6 +72,7 @@ func (f *federator) PostInboxRequestBodyHook(ctx context.Context, r *http.Reques | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	ctxWithActivity := context.WithValue(ctx, util.APActivity, activity) | 	ctxWithActivity := context.WithValue(ctx, util.APActivity, activity) | ||||||
| 	return ctxWithActivity, nil | 	return ctxWithActivity, nil | ||||||
| } | } | ||||||
|  | @ -100,14 +101,22 @@ func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWr | ||||||
| 	}) | 	}) | ||||||
| 	l.Trace("received request to authenticate") | 	l.Trace("received request to authenticate") | ||||||
| 
 | 
 | ||||||
| 	requestedAccountI := ctx.Value(util.APAccount) | 	if !util.IsInboxPath(r.URL) { | ||||||
| 	if requestedAccountI == nil { | 		return nil, false, fmt.Errorf("path %s was not an inbox path", r.URL.String()) | ||||||
| 		return ctx, false, errors.New("requested account not set in context") |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	requestedAccount, ok := requestedAccountI.(*gtsmodel.Account) | 	username, err := util.ParseInboxPath(r.URL) | ||||||
| 	if !ok || requestedAccount == nil { | 	if err != nil { | ||||||
| 		return ctx, false, errors.New("requested account not parsebale from context") | 		return nil, false, fmt.Errorf("could not parse path %s: %s", r.URL.String(), err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if username == "" { | ||||||
|  | 		return nil, false, errors.New("username was empty") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	requestedAccount := >smodel.Account{} | ||||||
|  | 	if err := f.db.GetLocalAccountByUsername(username, requestedAccount); err != nil { | ||||||
|  | 		return nil, false, fmt.Errorf("could not fetch requested account with username %s: %s", username, err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	publicKeyOwnerURI, err := f.AuthenticateFederatedRequest(requestedAccount.Username, r) | 	publicKeyOwnerURI, err := f.AuthenticateFederatedRequest(requestedAccount.Username, r) | ||||||
|  | @ -124,7 +133,6 @@ func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWr | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// we don't know this account (yet) so let's dereference it right now | 		// we don't know this account (yet) so let's dereference it right now | ||||||
| 		// TODO: slow-fed |  | ||||||
| 		person, err := f.DereferenceRemoteAccount(requestedAccount.Username, publicKeyOwnerURI) | 		person, err := f.DereferenceRemoteAccount(requestedAccount.Username, publicKeyOwnerURI) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return ctx, false, fmt.Errorf("error dereferencing account with public key id %s: %s", publicKeyOwnerURI.String(), err) | 			return ctx, false, fmt.Errorf("error dereferencing account with public key id %s: %s", publicKeyOwnerURI.String(), err) | ||||||
|  | @ -138,7 +146,6 @@ func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWr | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	contextWithRequestingAccount := context.WithValue(ctx, util.APRequestingAccount, requestingAccount) | 	contextWithRequestingAccount := context.WithValue(ctx, util.APRequestingAccount, requestingAccount) | ||||||
| 
 |  | ||||||
| 	return contextWithRequestingAccount, true, nil | 	return contextWithRequestingAccount, true, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -180,9 +187,9 @@ func (f *federator) Blocked(ctx context.Context, actorIRIs []*url.URL) (bool, er | ||||||
| // | // | ||||||
| // Applications are not expected to handle every single ActivityStreams | // Applications are not expected to handle every single ActivityStreams | ||||||
| // type and extension. The unhandled ones are passed to DefaultCallback. | // type and extension. The unhandled ones are passed to DefaultCallback. | ||||||
| func (f *federator) FederatingCallbacks(ctx context.Context) (pub.FederatingWrappedCallbacks, []interface{}, error) { | func (f *federator) FederatingCallbacks(ctx context.Context) (wrapped pub.FederatingWrappedCallbacks, other []interface{}, err error) { | ||||||
| 	// TODO | 
 | ||||||
| 	return pub.FederatingWrappedCallbacks{}, nil, nil | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DefaultCallback is called for types that go-fed can deserialize but | // DefaultCallback is called for types that go-fed can deserialize but | ||||||
|  | @ -207,7 +214,7 @@ func (f *federator) DefaultCallback(ctx context.Context, activity pub.Activity) | ||||||
| // Zero or negative numbers indicate infinite recursion. | // Zero or negative numbers indicate infinite recursion. | ||||||
| func (f *federator) MaxInboxForwardingRecursionDepth(ctx context.Context) int { | func (f *federator) MaxInboxForwardingRecursionDepth(ctx context.Context) int { | ||||||
| 	// TODO | 	// TODO | ||||||
| 	return 0 | 	return 4 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // MaxDeliveryRecursionDepth determines how deep to search within | // MaxDeliveryRecursionDepth determines how deep to search within | ||||||
|  | @ -217,7 +224,7 @@ func (f *federator) MaxInboxForwardingRecursionDepth(ctx context.Context) int { | ||||||
| // Zero or negative numbers indicate infinite recursion. | // Zero or negative numbers indicate infinite recursion. | ||||||
| func (f *federator) MaxDeliveryRecursionDepth(ctx context.Context) int { | func (f *federator) MaxDeliveryRecursionDepth(ctx context.Context) int { | ||||||
| 	// TODO | 	// TODO | ||||||
| 	return 0 | 	return 4 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // FilterForwarding allows the implementation to apply business logic | // FilterForwarding allows the implementation to apply business logic | ||||||
|  | @ -241,7 +248,7 @@ func (f *federator) FilterForwarding(ctx context.Context, potentialRecipients [] | ||||||
| // Always called, regardless whether the Federated Protocol or Social | // Always called, regardless whether the Federated Protocol or Social | ||||||
| // API is enabled. | // API is enabled. | ||||||
| func (f *federator) GetInbox(ctx context.Context, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error) { | func (f *federator) GetInbox(ctx context.Context, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error) { | ||||||
| 	// IMPLEMENTATION NOTE: For GoToSocial, we serve outboxes and inboxes through | 	// IMPLEMENTATION NOTE: For GoToSocial, we serve GETS to outboxes and inboxes through | ||||||
| 	// the CLIENT API, not through the federation API, so we just do nothing here. | 	// the CLIENT API, not through the federation API, so we just do nothing here. | ||||||
| 	return nil, nil | 	return nil, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| package message | package message | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 
 | 
 | ||||||
|  | @ -8,6 +9,7 @@ import ( | ||||||
| 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" | 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/db" | 	"github.com/superseriousbusiness/gotosocial/internal/db" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/util" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // authenticateAndDereferenceFediRequest authenticates the HTTP signature of an incoming federation request, using the given | // authenticateAndDereferenceFediRequest authenticates the HTTP signature of an incoming federation request, using the given | ||||||
|  | @ -130,3 +132,9 @@ func (p *processor) GetWebfingerAccount(requestedUsername string, request *http. | ||||||
| 		}, | 		}, | ||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (p *processor) InboxPost(ctx context.Context, w http.ResponseWriter, r *http.Request) (bool, error) { | ||||||
|  | 	contextWithChannel := context.WithValue(ctx, util.APFromFederatorChanKey, p.fromFederator) | ||||||
|  | 	posted, err := p.federator.FederatingActor().PostInbox(contextWithChannel, w, r) | ||||||
|  | 	return posted, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ | ||||||
| package message | package message | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 
 | 
 | ||||||
| 	"github.com/sirupsen/logrus" | 	"github.com/sirupsen/logrus" | ||||||
|  | @ -116,6 +117,18 @@ type Processor interface { | ||||||
| 
 | 
 | ||||||
| 	// GetWebfingerAccount handles the GET for a webfinger resource. Most commonly, it will be used for returning account lookups. | 	// 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) | 	GetWebfingerAccount(requestedUsername string, request *http.Request) (*apimodel.WebfingerAccountResponse, ErrorWithCode) | ||||||
|  | 
 | ||||||
|  | 	// InboxPost handles POST requests to a user's inbox for new activitypub messages. | ||||||
|  | 	// | ||||||
|  | 	// InboxPost returns true if the request was handled as an ActivityPub POST to an actor's inbox. | ||||||
|  | 	// If false, the request was not an ActivityPub request and may still be handled by the caller in another way, such as serving a web page. | ||||||
|  | 	// | ||||||
|  | 	// If the error is nil, then the ResponseWriter's headers and response has already been written. If a non-nil error is returned, then no response has been written. | ||||||
|  | 	// | ||||||
|  | 	// If the Actor was constructed with the Federated Protocol enabled, side effects will occur. | ||||||
|  | 	// | ||||||
|  | 	// If the Federated Protocol is not enabled, writes the http.StatusMethodNotAllowed status code in the response. No side effects occur. | ||||||
|  | 	InboxPost(ctx context.Context, w http.ResponseWriter, r *http.Request) (bool, error) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // processor just implements the Processor interface | // processor just implements the Processor interface | ||||||
|  |  | ||||||
|  | @ -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) { | func (c *controller) NewTransport(pubKeyID string, privkey crypto.PrivateKey) (pub.Transport, error) { | ||||||
| 	prefs := []httpsig.Algorithm{httpsig.RSA_SHA256, httpsig.RSA_SHA512} | 	prefs := []httpsig.Algorithm{httpsig.RSA_SHA256, httpsig.RSA_SHA512} | ||||||
| 	digestAlgo := httpsig.DigestSha256 | 	digestAlgo := httpsig.DigestSha256 | ||||||
| 	getHeaders := []string{"(request-target)", "date", "accept"} | 	getHeaders := []string{"(request-target)", "host", "date"} | ||||||
| 	postHeaders := []string{"(request-target)", "date", "accept", "digest"} | 	postHeaders := []string{"(request-target)", "host", "date", "digest"} | ||||||
| 
 | 
 | ||||||
| 	getSigner, _, err := httpsig.NewSigner(prefs, digestAlgo, getHeaders, httpsig.Signature) | 	getSigner, _, err := httpsig.NewSigner(prefs, digestAlgo, getHeaders, httpsig.Signature) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  |  | ||||||
|  | @ -61,6 +61,8 @@ const ( | ||||||
| 	APRequestingAccount APContextKey = "requestingAccount" | 	APRequestingAccount APContextKey = "requestingAccount" | ||||||
| 	// APRequestingPublicKeyID can be used to set and retrieve the public key ID of an incoming federation request. | 	// APRequestingPublicKeyID can be used to set and retrieve the public key ID of an incoming federation request. | ||||||
| 	APRequestingPublicKeyID APContextKey = "requestingPublicKeyID" | 	APRequestingPublicKeyID APContextKey = "requestingPublicKeyID" | ||||||
|  | 	// APFromFederatorChanKey can be used to pass a pointer to the fromFederator channel into the federator for use in callbacks. | ||||||
|  | 	APFromFederatorChanKey APContextKey = "fromFederatorChan" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type ginContextKey struct{} | type ginContextKey struct{} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue