diff options
| author | 2023-12-18 14:18:25 +0000 | |
|---|---|---|
| committer | 2023-12-18 14:18:25 +0000 | |
| commit | 8ebb7775a35b632d49a8f294d83ac786666631f3 (patch) | |
| tree | 02ac5475274125170132b0a4d9f69bd67491a32c /internal/api/client | |
| parent | fix poll total vote double count (#2464) (diff) | |
| download | gotosocial-8ebb7775a35b632d49a8f294d83ac786666631f3.tar.xz | |
[feature] request blocking by http headers (#2409)
Diffstat (limited to 'internal/api/client')
| -rw-r--r-- | internal/api/client/admin/admin.go | 14 | ||||
| -rw-r--r-- | internal/api/client/admin/headerfilter.go | 173 | ||||
| -rw-r--r-- | internal/api/client/admin/headerfilter_create.go | 102 | ||||
| -rw-r--r-- | internal/api/client/admin/headerfilter_delete.go | 96 | ||||
| -rw-r--r-- | internal/api/client/admin/headerfilter_get.go | 164 | 
5 files changed, 549 insertions, 0 deletions
diff --git a/internal/api/client/admin/admin.go b/internal/api/client/admin/admin.go index 16c5fa8f8..6173218e0 100644 --- a/internal/api/client/admin/admin.go +++ b/internal/api/client/admin/admin.go @@ -35,6 +35,10 @@ const (  	DomainAllowsPath        = BasePath + "/domain_allows"  	DomainAllowsPathWithID  = DomainAllowsPath + "/:" + IDKey  	DomainKeysExpirePath    = BasePath + "/domain_keys_expire" +	HeaderAllowsPath        = BasePath + "/header_allows" +	HeaderAllowsPathWithID  = HeaderAllowsPath + "/:" + IDKey +	HeaderBlocksPath        = BasePath + "/header_blocks" +	HeaderBlocksPathWithID  = HeaderAllowsPath + "/:" + IDKey  	AccountsPath            = BasePath + "/accounts"  	AccountsPathWithID      = AccountsPath + "/:" + IDKey  	AccountsActionPath      = AccountsPathWithID + "/action" @@ -95,6 +99,16 @@ func (m *Module) Route(attachHandler func(method string, path string, f ...gin.H  	attachHandler(http.MethodGet, DomainAllowsPathWithID, m.DomainAllowGETHandler)  	attachHandler(http.MethodDelete, DomainAllowsPathWithID, m.DomainAllowDELETEHandler) +	// header filtering administration routes +	attachHandler(http.MethodGet, HeaderAllowsPathWithID, m.HeaderFilterAllowGET) +	attachHandler(http.MethodGet, HeaderBlocksPathWithID, m.HeaderFilterBlockGET) +	attachHandler(http.MethodGet, HeaderAllowsPath, m.HeaderFilterAllowsGET) +	attachHandler(http.MethodGet, HeaderBlocksPath, m.HeaderFilterBlocksGET) +	attachHandler(http.MethodPost, HeaderAllowsPath, m.HeaderFilterAllowPOST) +	attachHandler(http.MethodPost, HeaderBlocksPath, m.HeaderFilterBlockPOST) +	attachHandler(http.MethodDelete, HeaderAllowsPathWithID, m.HeaderFilterAllowDELETE) +	attachHandler(http.MethodDelete, HeaderBlocksPathWithID, m.HeaderFilterBlockDELETE) +  	// domain maintenance stuff  	attachHandler(http.MethodPost, DomainKeysExpirePath, m.DomainKeysExpirePOSTHandler) diff --git a/internal/api/client/admin/headerfilter.go b/internal/api/client/admin/headerfilter.go new file mode 100644 index 000000000..7b1a85c86 --- /dev/null +++ b/internal/api/client/admin/headerfilter.go @@ -0,0 +1,173 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// 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 admin + +import ( +	"context" +	"errors" +	"net/http" + +	"github.com/gin-gonic/gin" +	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" +	apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" +	"github.com/superseriousbusiness/gotosocial/internal/gtserror" +	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/oauth" +) + +// getHeaderFilter is a gin handler function that returns details of an HTTP header filter with provided ID, using given get function. +func (m *Module) getHeaderFilter(c *gin.Context, get func(context.Context, string) (*apimodel.HeaderFilter, gtserror.WithCode)) { +	authed, err := oauth.Authed(c, true, true, true, true) +	if err != nil { +		errWithCode := gtserror.NewErrorUnauthorized(err, err.Error()) +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	if !*authed.User.Admin { +		const text = "user not an admin" +		errWithCode := gtserror.NewErrorForbidden(errors.New(text), text) +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil { +		errWithCode := gtserror.NewErrorNotAcceptable(err, err.Error()) +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	filterID, errWithCode := apiutil.ParseID(c.Param("ID")) +	if errWithCode != nil { +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	filter, errWithCode := get(c.Request.Context(), filterID) +	if errWithCode != nil { +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	apiutil.JSON(c, http.StatusOK, filter) +} + +// getHeaderFilters is a gin handler function that returns details of all HTTP header filters using given get function. +func (m *Module) getHeaderFilters(c *gin.Context, get func(context.Context) ([]*apimodel.HeaderFilter, gtserror.WithCode)) { +	authed, err := oauth.Authed(c, true, true, true, true) +	if err != nil { +		errWithCode := gtserror.NewErrorUnauthorized(err, err.Error()) +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	if !*authed.User.Admin { +		const text = "user not an admin" +		errWithCode := gtserror.NewErrorForbidden(errors.New(text), text) +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil { +		errWithCode := gtserror.NewErrorNotAcceptable(err, err.Error()) +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	filters, errWithCode := get(c.Request.Context()) +	if errWithCode != nil { +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	apiutil.JSON(c, http.StatusOK, filters) +} + +// createHeaderFilter is a gin handler function that creates a HTTP header filter entry using provided form data, passing to given create function. +func (m *Module) createHeaderFilter(c *gin.Context, create func(context.Context, *gtsmodel.Account, *apimodel.HeaderFilterRequest) (*apimodel.HeaderFilter, gtserror.WithCode)) { +	authed, err := oauth.Authed(c, true, true, true, true) +	if err != nil { +		errWithCode := gtserror.NewErrorUnauthorized(err, err.Error()) +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	if !*authed.User.Admin { +		const text = "user not an admin" +		errWithCode := gtserror.NewErrorForbidden(errors.New(text), text) +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil { +		errWithCode := gtserror.NewErrorNotAcceptable(err, err.Error()) +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	var form apimodel.HeaderFilterRequest + +	if err := c.ShouldBind(&form); err != nil { +		errWithCode := gtserror.NewErrorBadRequest(err, err.Error()) +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	filter, errWithCode := create( +		c.Request.Context(), +		authed.Account, +		&form, +	) +	if errWithCode != nil { +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	apiutil.JSON(c, http.StatusOK, filter) +} + +// deleteHeaderFilter is a gin handler function that deletes an HTTP header filter with provided ID, using given delete function. +func (m *Module) deleteHeaderFilter(c *gin.Context, delete func(context.Context, string) gtserror.WithCode) { +	authed, err := oauth.Authed(c, true, true, true, true) +	if err != nil { +		errWithCode := gtserror.NewErrorUnauthorized(err, err.Error()) +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	if !*authed.User.Admin { +		const text = "user not an admin" +		errWithCode := gtserror.NewErrorForbidden(errors.New(text), text) +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	filterID, errWithCode := apiutil.ParseID(c.Param("ID")) +	if errWithCode != nil { +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	errWithCode = delete(c.Request.Context(), filterID) +	if errWithCode != nil { +		apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) +		return +	} + +	c.Status(http.StatusAccepted) +} diff --git a/internal/api/client/admin/headerfilter_create.go b/internal/api/client/admin/headerfilter_create.go new file mode 100644 index 000000000..d74dc5e15 --- /dev/null +++ b/internal/api/client/admin/headerfilter_create.go @@ -0,0 +1,102 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// 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 admin + +import ( +	"github.com/gin-gonic/gin" +) + +// HeaderFilterAllowPOST swagger:operation POST /api/v1/admin/header_allows headerFilterAllowCreate +// +// Create new "allow" HTTP request header filter. +// +// The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. +// The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. +// +//	--- +//	tags: +//	- admin +// +//	consumes: +//	- application/json +//	- application/xml +//	- application/x-www-form-urlencoded +// +//	produces: +//	- application/json +// +//	security: +//	- OAuth2 Bearer: +//		- admin +// +//	responses: +//		'200': +//			description: The newly created "allow" header filter. +//			schema: +//				"$ref": "#/definitions/headerFilter" +//		'400': +//			description: bad request +//		'401': +//			description: unauthorized +//		'403': +//			description: forbidden +//		'500': +//			description: internal server error +func (m *Module) HeaderFilterAllowPOST(c *gin.Context) { +	m.createHeaderFilter(c, m.processor.Admin().CreateAllowHeaderFilter) +} + +// HeaderFilterBlockPOST swagger:operation POST /api/v1/admin/header_blocks headerFilterBlockCreate +// +// Create new "block" HTTP request header filter. +// +// The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. +// The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. +// +//	--- +//	tags: +//	- admin +// +//	consumes: +//	- application/json +//	- application/xml +//	- application/x-www-form-urlencoded +// +//	produces: +//	- application/json +// +//	security: +//	- OAuth2 Bearer: +//		- admin +// +//	responses: +//		'200': +//			description: The newly created "block" header filter. +//			schema: +//				"$ref": "#/definitions/headerFilter" +//		'400': +//			description: bad request +//		'401': +//			description: unauthorized +//		'403': +//			description: forbidden +//		'500': +//			description: internal server error +func (m *Module) HeaderFilterBlockPOST(c *gin.Context) { +	m.createHeaderFilter(c, m.processor.Admin().CreateBlockHeaderFilter) +} diff --git a/internal/api/client/admin/headerfilter_delete.go b/internal/api/client/admin/headerfilter_delete.go new file mode 100644 index 000000000..806e62a04 --- /dev/null +++ b/internal/api/client/admin/headerfilter_delete.go @@ -0,0 +1,96 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// 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 admin + +import ( +	"github.com/gin-gonic/gin" +) + +// HeaderFilterAllowDELETE swagger:operation DELETE /api/v1/admin/header_allows/{id} headerFilterAllowDelete +// +// Delete the "allow" header filter with the given ID. +// +//	--- +//	tags: +//	- admin +// +//	parameters: +//	- +//		name: id +//		type: string +//		description: Target header filter ID. +//		in: path +//		required: true +// +//	security: +//	- OAuth2 Bearer: +//		- admin +// +//	responses: +//		'202': +//			description: Accepted +//		'400': +//			description: bad request +//		'401': +//			description: unauthorized +//		'403': +//			description: forbidden +//		'404': +//			description: not found +//		'500': +//			description: internal server error +func (m *Module) HeaderFilterAllowDELETE(c *gin.Context) { +	m.deleteHeaderFilter(c, m.processor.Admin().DeleteAllowHeaderFilter) +} + +// HeaderFilterBlockDELETE swagger:operation DELETE /api/v1/admin/header_blocks/{id} headerFilterBlockDelete +// +// Delete the "block" header filter with the given ID. +// +//	--- +//	tags: +//	- admin +// +//	parameters: +//	- +//		name: id +//		type: string +//		description: Target header filter ID. +//		in: path +//		required: true +// +//	security: +//	- OAuth2 Bearer: +//		- admin +// +//	responses: +//		'202': +//			description: Accepted +//		'400': +//			description: bad request +//		'401': +//			description: unauthorized +//		'403': +//			description: forbidden +//		'404': +//			description: not found +//		'500': +//			description: internal server error +func (m *Module) HeaderFilterBlockDELETE(c *gin.Context) { +	m.deleteHeaderFilter(c, m.processor.Admin().DeleteAllowHeaderFilter) +} diff --git a/internal/api/client/admin/headerfilter_get.go b/internal/api/client/admin/headerfilter_get.go new file mode 100644 index 000000000..5bca6d18d --- /dev/null +++ b/internal/api/client/admin/headerfilter_get.go @@ -0,0 +1,164 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// 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 admin + +import "github.com/gin-gonic/gin" + +// HeaderFilterAllowGET swagger:operation GET /api/v1/admin/header_allows/{id} headerFilterAllowGet +// +// Get "allow" header filter with the given ID. +// +//	--- +//	tags: +//	- admin +// +//	parameters: +//	- +//		name: id +//		type: string +//		description: Target header filter ID. +//		in: path +//		required: true +// +//	security: +//	- OAuth2 Bearer: +//		- admin +// +//	responses: +//		'200': +//			description: The requested "allow" header filter. +//			schema: +//				"$ref": "#/definitions/headerFilter" +//		'400': +//			description: bad request +//		'401': +//			description: unauthorized +//		'403': +//			description: forbidden +//		'404': +//			description: not found +//		'500': +//			description: internal server error +func (m *Module) HeaderFilterAllowGET(c *gin.Context) { +	m.getHeaderFilter(c, m.processor.Admin().GetAllowHeaderFilter) +} + +// HeaderFilterBlockGET swagger:operation GET /api/v1/admin/header_blocks/{id} headerFilterBlockGet +// +// Get "block" header filter with the given ID. +// +//	--- +//	tags: +//	- admin +// +//	parameters: +//	- +//		name: id +//		type: string +//		description: Target header filter ID. +//		in: path +//		required: true +// +//	security: +//	- OAuth2 Bearer: +//		- admin +// +//	responses: +//		'200': +//			description: The requested "block" header filter. +//			schema: +//				"$ref": "#/definitions/headerFilter" +//		'400': +//			description: bad request +//		'401': +//			description: unauthorized +//		'403': +//			description: forbidden +//		'404': +//			description: not found +//		'500': +//			description: internal server error +func (m *Module) HeaderFilterBlockGET(c *gin.Context) { +	m.getHeaderFilter(c, m.processor.Admin().GetBlockHeaderFilter) +} + +// HeaderFilterAllowsGET swagger:operation GET /api/v1/admin/header_allows headerFilterAllowsGet +// +// Get all "allow" header filters currently in place. +// +//	--- +//	tags: +//	- admin +// +//	security: +//	- OAuth2 Bearer: +//		- admin +// +//	responses: +//		'200': +//			description: All "allow" header filters currently in place. +//			schema: +//				type: array +//				items: +//					"$ref": "#/definitions/headerFilter" +//		'400': +//			description: bad request +//		'401': +//			description: unauthorized +//		'403': +//			description: forbidden +//		'404': +//			description: not found +//		'500': +//			description: internal server error +func (m *Module) HeaderFilterAllowsGET(c *gin.Context) { +	m.getHeaderFilters(c, m.processor.Admin().GetAllowHeaderFilters) +} + +// HeaderFilterBlocksGET swagger:operation GET /api/v1/admin/header_blocks headerFilterBlocksGet +// +// Get all "allow" header filters currently in place. +// +//	--- +//	tags: +//	- admin +// +//	security: +//	- OAuth2 Bearer: +//		- admin +// +//	responses: +//		'200': +//			description: All "block" header filters currently in place. +//			schema: +//				type: array +//				items: +//					"$ref": "#/definitions/headerFilter" +//		'400': +//			description: bad request +//		'401': +//			description: unauthorized +//		'403': +//			description: forbidden +//		'404': +//			description: not found +//		'500': +//			description: internal server error +func (m *Module) HeaderFilterBlocksGET(c *gin.Context) { +	m.getHeaderFilters(c, m.processor.Admin().GetBlockHeaderFilters) +}  | 
