Anti CSRF layer
							parent
							
								
									aa79b076ae
								
							
						
					
					
						commit
						37c77a3cee
					
				
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -420,6 +420,10 @@ pre { | |||
|     box-sizing: border-box; | ||||
| } | ||||
| 
 | ||||
| #token { | ||||
|     display: none; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* MATERIAL ICONS */ | ||||
| 
 | ||||
|  | @ -1103,4 +1107,4 @@ i.spin { | |||
|         column-count: 1; | ||||
|         column-gap: 0; | ||||
|     } | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| 
 | ||||
| const tempID = "_fm_internal_temporary_id" | ||||
| var selectedItems = []; | ||||
| var token = ""; | ||||
| 
 | ||||
| /* * * * * * * * * * * * * * * * | ||||
|  *                             * | ||||
|  | @ -115,6 +116,7 @@ var deleteEvent = function(event) { | |||
|             let request = new XMLHttpRequest(); | ||||
| 
 | ||||
|             request.open('DELETE', link); | ||||
|             request.setRequestHeader('Token', token); | ||||
|             request.send(); | ||||
|             request.onreadystatechange = function() { | ||||
|                 if (request.readyState == 4) { | ||||
|  | @ -165,6 +167,11 @@ var RemoveLastDirectoryPartOf = function(url) { | |||
|     return (arr.join('/')); | ||||
| } | ||||
| 
 | ||||
| // Get the current token
 | ||||
| var updateToken = function() { | ||||
|     token = document.getElementById("token").innerHTML; | ||||
| } | ||||
| 
 | ||||
| /* * * * * * * * * * * * * * * * | ||||
|  *                             * | ||||
|  *  LISTING SPECIFIC FUNCTIONS  * | ||||
|  | @ -175,6 +182,7 @@ var reloadListing = function() { | |||
|     let request = new XMLHttpRequest(); | ||||
|     request.open('GET', window.location); | ||||
|     request.setRequestHeader('Minimal', 'true'); | ||||
|     request.setRequestHeader('Token', token); | ||||
|     request.send(); | ||||
|     request.onreadystatechange = function() { | ||||
|         if (request.readyState == 4) { | ||||
|  | @ -186,6 +194,7 @@ var reloadListing = function() { | |||
|             } | ||||
|         } | ||||
|     } | ||||
|     updateToken(); | ||||
| } | ||||
| 
 | ||||
| // Rename file event
 | ||||
|  | @ -217,6 +226,7 @@ var renameEvent = function(event) { | |||
|                 let request = new XMLHttpRequest(); | ||||
|                 request.open('PATCH', link); | ||||
|                 request.setRequestHeader('Rename-To', newName); | ||||
|                 request.setRequestHeader('Token', token); | ||||
|                 request.send(); | ||||
|                 request.onreadystatechange = function() { | ||||
|                     if (request.readyState == 4) { | ||||
|  | @ -274,6 +284,7 @@ var handleFiles = function(files) { | |||
|     let request = new XMLHttpRequest(); | ||||
|     request.open('POST', window.location.pathname); | ||||
|     request.setRequestHeader("Upload", "true"); | ||||
|     request.setRequestHeader('Token', token); | ||||
|     request.send(data); | ||||
|     request.onreadystatechange = function() { | ||||
|         if (request.readyState == 4) { | ||||
|  | @ -382,6 +393,7 @@ var newDirEvent = function(event) { | |||
|         let html = button.changeToLoading(); | ||||
|         let request = new XMLHttpRequest(); | ||||
|         request.open("POST", window.location); | ||||
|         request.setRequestHeader('Token', token); | ||||
|         request.setRequestHeader('Filename', document.getElementById('newdir').value); | ||||
|         request.send(); | ||||
|         request.onreadystatechange = function() { | ||||
|  | @ -444,6 +456,7 @@ var searchEvent = function(event) { | |||
|         let request = new XMLHttpRequest(); | ||||
|         request.open('POST', window.location); | ||||
|         request.setRequestHeader('Command', value); | ||||
|         request.setRequestHeader('Token', token); | ||||
|         request.send(); | ||||
|         request.onreadystatechange = function() { | ||||
|             if (request.readyState == 4) { | ||||
|  | @ -751,6 +764,7 @@ document.addEventListener("editor", (event) => { | |||
|         let request = new XMLHttpRequest(); | ||||
|         request.open("PUT", window.location); | ||||
|         request.setRequestHeader('Kind', kind); | ||||
|         request.setRequestHeader('Token', token); | ||||
|         request.send(JSON.stringify(data)); | ||||
|         request.onreadystatechange = function() { | ||||
|             if (request.readyState == 4) { | ||||
|  | @ -781,6 +795,9 @@ document.addEventListener("DOMContentLoaded", function(event) { | |||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     // Updates the token
 | ||||
|     updateToken(); | ||||
| 
 | ||||
|     // Enables open, delete and download buttons
 | ||||
|     document.getElementById("open").addEventListener("click", openEvent); | ||||
|     document.getElementById("delete").addEventListener("click", deleteEvent); | ||||
|  |  | |||
|  | @ -104,6 +104,7 @@ | |||
| 
 | ||||
|   <main> | ||||
|    {{ template "content" .Data }} | ||||
|    <span id="token">{{ .Config.Token }}</span> | ||||
|   </main> | ||||
| 
 | ||||
|   <footer> | ||||
|  |  | |||
|  | @ -1 +1,2 @@ | |||
| {{ template "content" .Data }} | ||||
| <span id="token">{{ .Config.Token }}</span> | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ type Config struct { | |||
| 	BaseURL     string | ||||
| 	AbsoluteURL string | ||||
| 	AddrPath    string | ||||
| 	Token       string // Anti CSRF token
 | ||||
| 	StyleSheet  string // Costum stylesheet
 | ||||
| 	FrontMatter string // Default frontmatter to save files in
 | ||||
| 	HugoEnabled bool   // Enables the Hugo plugin for File Manager
 | ||||
|  |  | |||
|  | @ -0,0 +1,42 @@ | |||
| package config | ||||
| 
 | ||||
| import ( | ||||
| 	"math/rand" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" | ||||
| const ( | ||||
| 	letterIdxBits = 6                    // 6 bits to represent a letter index
 | ||||
| 	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
 | ||||
| 	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
 | ||||
| ) | ||||
| 
 | ||||
| // CheckToken checs if current token is the same as the one used in the request
 | ||||
| func (c Config) CheckToken(r *http.Request) bool { | ||||
| 	token := r.Header.Get("Token") | ||||
| 	return c.Token == token | ||||
| } | ||||
| 
 | ||||
| // GenerateToken geneerates a new token
 | ||||
| func (c *Config) GenerateToken() { | ||||
| 	n := rand.Intn(80) | ||||
| 	src := rand.NewSource(time.Now().UnixNano()) | ||||
| 	b := make([]byte, n) | ||||
| 	// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
 | ||||
| 	// future reference: http://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang
 | ||||
| 	for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; { | ||||
| 		if remain == 0 { | ||||
| 			cache, remain = src.Int63(), letterIdxMax | ||||
| 		} | ||||
| 		if idx := int(cache & letterIdxMask); idx < len(letterBytes) { | ||||
| 			b[i] = letterBytes[idx] | ||||
| 			i-- | ||||
| 		} | ||||
| 		cache >>= letterIdxBits | ||||
| 		remain-- | ||||
| 	} | ||||
| 
 | ||||
| 	c.Token = string(b) | ||||
| } | ||||
|  | @ -8,6 +8,7 @@ | |||
| package filemanager | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
|  | @ -59,6 +60,13 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err | |||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Secure agains CSRF attacks
 | ||||
| 			if r.Method != http.MethodGet { | ||||
| 				if !c.CheckToken(r) { | ||||
| 					return http.StatusForbidden, nil | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Route the request depending on the HTTP Method
 | ||||
| 			switch r.Method { | ||||
| 			case http.MethodGet: | ||||
|  | @ -67,6 +75,9 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err | |||
| 					return assets.Serve(w, r, c) | ||||
| 				} | ||||
| 
 | ||||
| 				c.GenerateToken() | ||||
| 				fmt.Println(c.Token) | ||||
| 
 | ||||
| 				if !fi.IsDir { | ||||
| 					query := r.URL.Query() | ||||
| 					if val, ok := query["raw"]; ok && val[0] == "true" { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Henrique Dias
						Henrique Dias