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