mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 06:22:25 -05:00 
			
		
		
		
	some formatting changes, include userAgent in nollamas logs, ignore requests with HTTP sigs
This commit is contained in:
		
					parent
					
						
							
								e4ba68e4e3
							
						
					
				
			
			
				commit
				
					
						a9f4217e92
					
				
			
		
					 2 changed files with 55 additions and 34 deletions
				
			
		|  | @ -33,6 +33,7 @@ import ( | ||||||
| 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" | 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" | ||||||
| 	apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" | 	apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/config" | 	"github.com/superseriousbusiness/gotosocial/internal/config" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/gtscontext" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/log" | 	"github.com/superseriousbusiness/gotosocial/internal/log" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/oauth" | 	"github.com/superseriousbusiness/gotosocial/internal/oauth" | ||||||
|  | @ -100,13 +101,23 @@ func (m *nollamas) Serve(c *gin.Context) { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if _, ok := c.Get(oauth.SessionAuthorizedToken); ok { | 	// Extract request context. | ||||||
|  | 	ctx := c.Request.Context() | ||||||
|  | 
 | ||||||
|  | 	if ctx.Value(oauth.SessionAuthorizedToken) != nil { | ||||||
| 		// Don't guard against requests | 		// Don't guard against requests | ||||||
| 		// providing valid OAuth tokens. | 		// providing valid OAuth tokens. | ||||||
| 		c.Next() | 		c.Next() | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if gtscontext.HTTPSignature(ctx) != "" { | ||||||
|  | 		// Don't guard against requests | ||||||
|  | 		// providing HTTP signatures. | ||||||
|  | 		c.Next() | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// i.e. outputted hash slice length. | 	// i.e. outputted hash slice length. | ||||||
| 	const hashLen = sha256.Size | 	const hashLen = sha256.Size | ||||||
| 
 | 
 | ||||||
|  | @ -120,21 +131,21 @@ func (m *nollamas) Serve(c *gin.Context) { | ||||||
| 		ebuf: make([]byte, encodedHashLen), | 		ebuf: make([]byte, encodedHashLen), | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Generate a unique token for | 	// Extract client fingerprint data. | ||||||
| 	// this request only valid for | 	userAgent := c.GetHeader("User-Agent") | ||||||
| 	// a period of now +- m.ttl. | 	clientIP := c.ClientIP() | ||||||
| 	token := m.token(c, &hash) | 
 | ||||||
|  | 	// Generate a unique token for this request, | ||||||
|  | 	// only valid for a period of now +- m.ttl. | ||||||
|  | 	token := m.token(&hash, userAgent, clientIP) | ||||||
| 
 | 
 | ||||||
| 	// For unique challenge string just use a | 	// For unique challenge string just use a | ||||||
| 	// repeated portion of their 'success' token. | 	// single portion of their 'success' token. | ||||||
| 	// SHA256 is not yet cracked, this is not an | 	// SHA256 is not yet cracked, this is not an | ||||||
| 	// application of a hash requiring serious | 	// application of a hash requiring serious | ||||||
| 	// cryptographic security and it rotates on | 	// cryptographic security and it rotates on | ||||||
| 	// a TTL basis, so it should be fine. | 	// a TTL basis, so it should be fine. | ||||||
| 	challenge := token[:len(token)/4] + | 	challenge := token[:len(token)/4] | ||||||
| 		token[:len(token)/4] + |  | ||||||
| 		token[:len(token)/4] + |  | ||||||
| 		token[:len(token)/4] |  | ||||||
| 
 | 
 | ||||||
| 	// Check for a provided success token. | 	// Check for a provided success token. | ||||||
| 	cookie, _ := c.Cookie("gts-nollamas") | 	cookie, _ := c.Cookie("gts-nollamas") | ||||||
|  | @ -152,9 +163,10 @@ func (m *nollamas) Serve(c *gin.Context) { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Prepare new log entry with challenge. | 	// Prepare new log entry. | ||||||
| 	l := log.WithContext(c.Request.Context()) | 	l := log.WithContext(ctx). | ||||||
| 	l = l.WithField("challenge", challenge[:len(challenge)/4]) | 		WithField("userAgent", userAgent). | ||||||
|  | 		WithField("challenge", challenge) | ||||||
| 
 | 
 | ||||||
| 	// Check query to see if an in-progress | 	// Check query to see if an in-progress | ||||||
| 	// challenge solution has been provided. | 	// challenge solution has been provided. | ||||||
|  | @ -174,25 +186,14 @@ func (m *nollamas) Serve(c *gin.Context) { | ||||||
| 	// Reset the hash. | 	// Reset the hash. | ||||||
| 	hash.hash.Reset() | 	hash.hash.Reset() | ||||||
| 
 | 
 | ||||||
| 	// Hash and encode input challenge with | 	// Check challenge+nonce as possible solution. | ||||||
| 	// proposed nonce as a possible solution. | 	if !m.checkChallenge(&hash, challenge, nonce) { | ||||||
| 	hash.hash.Write(byteutil.S2B(challenge)) |  | ||||||
| 	hash.hash.Write(byteutil.S2B(nonce)) |  | ||||||
| 	hash.hbuf = hash.hash.Sum(hash.hbuf[:0]) |  | ||||||
| 	hex.Encode(hash.ebuf, hash.hbuf) |  | ||||||
| 	solution := hash.ebuf |  | ||||||
| 
 | 
 | ||||||
| 	// Check that the first 'diff' | 		// They failed challenge, | ||||||
| 	// many chars are indeed zeroes. | 		// re-present challenge page. | ||||||
| 	for i := range m.diff { | 		l.Info("invalid solution provided") | ||||||
| 		if solution[i] != '0' { | 		m.renderChallenge(c, challenge) | ||||||
| 
 | 		return | ||||||
| 			// They failed challenge, |  | ||||||
| 			// re-present challenge page. |  | ||||||
| 			l.Warn("invalid solution provided") |  | ||||||
| 			m.renderChallenge(c, challenge) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	l.Infof("challenge passed: %s", nonce) | 	l.Infof("challenge passed: %s", nonce) | ||||||
|  | @ -234,7 +235,7 @@ func (m *nollamas) renderChallenge(c *gin.Context, challenge string) { | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (m *nollamas) token(c *gin.Context, hash *hashWithBufs) string { | func (m *nollamas) token(hash *hashWithBufs, userAgent, clientIP string) string { | ||||||
| 	// Use our unique seed to seed hash, | 	// Use our unique seed to seed hash, | ||||||
| 	// to ensure we have cryptographically | 	// to ensure we have cryptographically | ||||||
| 	// unique, yet deterministic, tokens | 	// unique, yet deterministic, tokens | ||||||
|  | @ -262,12 +263,31 @@ func (m *nollamas) token(c *gin.Context, hash *hashWithBufs) string { | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	// Finally, append unique client request data. | 	// Finally, append unique client request data. | ||||||
| 	userAgent := c.Request.Header.Get("User-Agent") |  | ||||||
| 	hash.hash.Write(byteutil.S2B(userAgent)) | 	hash.hash.Write(byteutil.S2B(userAgent)) | ||||||
| 	hash.hash.Write(byteutil.S2B(c.ClientIP())) | 	hash.hash.Write(byteutil.S2B(clientIP)) | ||||||
| 
 | 
 | ||||||
| 	// Return hex encoded hash output. | 	// Return hex encoded hash output. | ||||||
| 	hash.hbuf = hash.hash.Sum(hash.hbuf[:0]) | 	hash.hbuf = hash.hash.Sum(hash.hbuf[:0]) | ||||||
| 	hex.Encode(hash.ebuf, hash.hbuf) | 	hex.Encode(hash.ebuf, hash.hbuf) | ||||||
| 	return string(hash.ebuf) | 	return string(hash.ebuf) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (m *nollamas) checkChallenge(hash *hashWithBufs, challenge, nonce string) bool { | ||||||
|  | 	// Hash and encode input challenge with | ||||||
|  | 	// proposed nonce as a possible solution. | ||||||
|  | 	hash.hash.Write(byteutil.S2B(challenge)) | ||||||
|  | 	hash.hash.Write(byteutil.S2B(nonce)) | ||||||
|  | 	hash.hbuf = hash.hash.Sum(hash.hbuf[:0]) | ||||||
|  | 	hex.Encode(hash.ebuf, hash.hbuf) | ||||||
|  | 	solution := hash.ebuf | ||||||
|  | 
 | ||||||
|  | 	// Check that the first 'diff' | ||||||
|  | 	// many chars are indeed zeroes. | ||||||
|  | 	for i := range m.diff { | ||||||
|  | 		if solution[i] != '0' { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -47,6 +47,7 @@ func TestNoLLaMasMiddleware(t *testing.T) { | ||||||
| 	config.SetAdvancedScraperDeterrence(true) | 	config.SetAdvancedScraperDeterrence(true) | ||||||
| 	config.SetWebTemplateBaseDir("../../web/template") | 	config.SetWebTemplateBaseDir("../../web/template") | ||||||
| 
 | 
 | ||||||
|  | 	// Load templates into engine. | ||||||
| 	err := router.LoadTemplates(e) | 	err := router.LoadTemplates(e) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue