mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-04 00:11:04 +00:00 
			
		
		
		
	* initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
		
			
				
	
	
		
			143 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2012 The Gorilla Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
package context
 | 
						|
 | 
						|
import (
 | 
						|
	"net/http"
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	mutex sync.RWMutex
 | 
						|
	data  = make(map[*http.Request]map[interface{}]interface{})
 | 
						|
	datat = make(map[*http.Request]int64)
 | 
						|
)
 | 
						|
 | 
						|
// Set stores a value for a given key in a given request.
 | 
						|
func Set(r *http.Request, key, val interface{}) {
 | 
						|
	mutex.Lock()
 | 
						|
	if data[r] == nil {
 | 
						|
		data[r] = make(map[interface{}]interface{})
 | 
						|
		datat[r] = time.Now().Unix()
 | 
						|
	}
 | 
						|
	data[r][key] = val
 | 
						|
	mutex.Unlock()
 | 
						|
}
 | 
						|
 | 
						|
// Get returns a value stored for a given key in a given request.
 | 
						|
func Get(r *http.Request, key interface{}) interface{} {
 | 
						|
	mutex.RLock()
 | 
						|
	if ctx := data[r]; ctx != nil {
 | 
						|
		value := ctx[key]
 | 
						|
		mutex.RUnlock()
 | 
						|
		return value
 | 
						|
	}
 | 
						|
	mutex.RUnlock()
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// GetOk returns stored value and presence state like multi-value return of map access.
 | 
						|
func GetOk(r *http.Request, key interface{}) (interface{}, bool) {
 | 
						|
	mutex.RLock()
 | 
						|
	if _, ok := data[r]; ok {
 | 
						|
		value, ok := data[r][key]
 | 
						|
		mutex.RUnlock()
 | 
						|
		return value, ok
 | 
						|
	}
 | 
						|
	mutex.RUnlock()
 | 
						|
	return nil, false
 | 
						|
}
 | 
						|
 | 
						|
// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests.
 | 
						|
func GetAll(r *http.Request) map[interface{}]interface{} {
 | 
						|
	mutex.RLock()
 | 
						|
	if context, ok := data[r]; ok {
 | 
						|
		result := make(map[interface{}]interface{}, len(context))
 | 
						|
		for k, v := range context {
 | 
						|
			result[k] = v
 | 
						|
		}
 | 
						|
		mutex.RUnlock()
 | 
						|
		return result
 | 
						|
	}
 | 
						|
	mutex.RUnlock()
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if
 | 
						|
// the request was registered.
 | 
						|
func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) {
 | 
						|
	mutex.RLock()
 | 
						|
	context, ok := data[r]
 | 
						|
	result := make(map[interface{}]interface{}, len(context))
 | 
						|
	for k, v := range context {
 | 
						|
		result[k] = v
 | 
						|
	}
 | 
						|
	mutex.RUnlock()
 | 
						|
	return result, ok
 | 
						|
}
 | 
						|
 | 
						|
// Delete removes a value stored for a given key in a given request.
 | 
						|
func Delete(r *http.Request, key interface{}) {
 | 
						|
	mutex.Lock()
 | 
						|
	if data[r] != nil {
 | 
						|
		delete(data[r], key)
 | 
						|
	}
 | 
						|
	mutex.Unlock()
 | 
						|
}
 | 
						|
 | 
						|
// Clear removes all values stored for a given request.
 | 
						|
//
 | 
						|
// This is usually called by a handler wrapper to clean up request
 | 
						|
// variables at the end of a request lifetime. See ClearHandler().
 | 
						|
func Clear(r *http.Request) {
 | 
						|
	mutex.Lock()
 | 
						|
	clear(r)
 | 
						|
	mutex.Unlock()
 | 
						|
}
 | 
						|
 | 
						|
// clear is Clear without the lock.
 | 
						|
func clear(r *http.Request) {
 | 
						|
	delete(data, r)
 | 
						|
	delete(datat, r)
 | 
						|
}
 | 
						|
 | 
						|
// Purge removes request data stored for longer than maxAge, in seconds.
 | 
						|
// It returns the amount of requests removed.
 | 
						|
//
 | 
						|
// If maxAge <= 0, all request data is removed.
 | 
						|
//
 | 
						|
// This is only used for sanity check: in case context cleaning was not
 | 
						|
// properly set some request data can be kept forever, consuming an increasing
 | 
						|
// amount of memory. In case this is detected, Purge() must be called
 | 
						|
// periodically until the problem is fixed.
 | 
						|
func Purge(maxAge int) int {
 | 
						|
	mutex.Lock()
 | 
						|
	count := 0
 | 
						|
	if maxAge <= 0 {
 | 
						|
		count = len(data)
 | 
						|
		data = make(map[*http.Request]map[interface{}]interface{})
 | 
						|
		datat = make(map[*http.Request]int64)
 | 
						|
	} else {
 | 
						|
		min := time.Now().Unix() - int64(maxAge)
 | 
						|
		for r := range data {
 | 
						|
			if datat[r] < min {
 | 
						|
				clear(r)
 | 
						|
				count++
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	mutex.Unlock()
 | 
						|
	return count
 | 
						|
}
 | 
						|
 | 
						|
// ClearHandler wraps an http.Handler and clears request values at the end
 | 
						|
// of a request lifetime.
 | 
						|
func ClearHandler(h http.Handler) http.Handler {
 | 
						|
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		defer Clear(r)
 | 
						|
		h.ServeHTTP(w, r)
 | 
						|
	})
 | 
						|
}
 |