mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 23:12: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" | ||||
| 	apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/config" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtscontext" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/log" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/oauth" | ||||
|  | @ -100,13 +101,23 @@ func (m *nollamas) Serve(c *gin.Context) { | |||
| 		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 | ||||
| 		// providing valid OAuth tokens. | ||||
| 		c.Next() | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if gtscontext.HTTPSignature(ctx) != "" { | ||||
| 		// Don't guard against requests | ||||
| 		// providing HTTP signatures. | ||||
| 		c.Next() | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// i.e. outputted hash slice length. | ||||
| 	const hashLen = sha256.Size | ||||
| 
 | ||||
|  | @ -120,21 +131,21 @@ func (m *nollamas) Serve(c *gin.Context) { | |||
| 		ebuf: make([]byte, encodedHashLen), | ||||
| 	} | ||||
| 
 | ||||
| 	// Generate a unique token for | ||||
| 	// this request only valid for | ||||
| 	// a period of now +- m.ttl. | ||||
| 	token := m.token(c, &hash) | ||||
| 	// Extract client fingerprint data. | ||||
| 	userAgent := c.GetHeader("User-Agent") | ||||
| 	clientIP := c.ClientIP() | ||||
| 
 | ||||
| 	// 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 | ||||
| 	// repeated portion of their 'success' token. | ||||
| 	// single portion of their 'success' token. | ||||
| 	// SHA256 is not yet cracked, this is not an | ||||
| 	// application of a hash requiring serious | ||||
| 	// cryptographic security and it rotates on | ||||
| 	// a TTL basis, so it should be fine. | ||||
| 	challenge := token[:len(token)/4] + | ||||
| 		token[:len(token)/4] + | ||||
| 		token[:len(token)/4] + | ||||
| 		token[:len(token)/4] | ||||
| 	challenge := token[:len(token)/4] | ||||
| 
 | ||||
| 	// Check for a provided success token. | ||||
| 	cookie, _ := c.Cookie("gts-nollamas") | ||||
|  | @ -152,9 +163,10 @@ func (m *nollamas) Serve(c *gin.Context) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// Prepare new log entry with challenge. | ||||
| 	l := log.WithContext(c.Request.Context()) | ||||
| 	l = l.WithField("challenge", challenge[:len(challenge)/4]) | ||||
| 	// Prepare new log entry. | ||||
| 	l := log.WithContext(ctx). | ||||
| 		WithField("userAgent", userAgent). | ||||
| 		WithField("challenge", challenge) | ||||
| 
 | ||||
| 	// Check query to see if an in-progress | ||||
| 	// challenge solution has been provided. | ||||
|  | @ -174,26 +186,15 @@ func (m *nollamas) Serve(c *gin.Context) { | |||
| 	// Reset the hash. | ||||
| 	hash.hash.Reset() | ||||
| 
 | ||||
| 	// 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' { | ||||
| 	// Check challenge+nonce as possible solution. | ||||
| 	if !m.checkChallenge(&hash, challenge, nonce) { | ||||
| 
 | ||||
| 		// They failed challenge, | ||||
| 		// re-present challenge page. | ||||
| 			l.Warn("invalid solution provided") | ||||
| 		l.Info("invalid solution provided") | ||||
| 		m.renderChallenge(c, challenge) | ||||
| 		return | ||||
| 	} | ||||
| 	} | ||||
| 
 | ||||
| 	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, | ||||
| 	// to ensure we have cryptographically | ||||
| 	// unique, yet deterministic, tokens | ||||
|  | @ -262,12 +263,31 @@ func (m *nollamas) token(c *gin.Context, hash *hashWithBufs) string { | |||
| 	}) | ||||
| 
 | ||||
| 	// Finally, append unique client request data. | ||||
| 	userAgent := c.Request.Header.Get("User-Agent") | ||||
| 	hash.hash.Write(byteutil.S2B(userAgent)) | ||||
| 	hash.hash.Write(byteutil.S2B(c.ClientIP())) | ||||
| 	hash.hash.Write(byteutil.S2B(clientIP)) | ||||
| 
 | ||||
| 	// Return hex encoded hash output. | ||||
| 	hash.hbuf = hash.hash.Sum(hash.hbuf[:0]) | ||||
| 	hex.Encode(hash.ebuf, hash.hbuf) | ||||
| 	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.SetWebTemplateBaseDir("../../web/template") | ||||
| 
 | ||||
| 	// Load templates into engine. | ||||
| 	err := router.LoadTemplates(e) | ||||
| 	assert.NoError(t, err) | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue