mirror of
https://github.com/filebrowser/filebrowser.git
synced 2025-05-09 03:32:56 +00:00
Anti CSRF layer
This commit is contained in:
parent
aa79b076ae
commit
37c77a3cee
File diff suppressed because one or more lines are too long
@ -420,6 +420,10 @@ pre {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#token {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* MATERIAL ICONS */
|
/* MATERIAL ICONS */
|
||||||
|
|
||||||
@ -1103,4 +1107,4 @@ i.spin {
|
|||||||
column-count: 1;
|
column-count: 1;
|
||||||
column-gap: 0;
|
column-gap: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const tempID = "_fm_internal_temporary_id"
|
const tempID = "_fm_internal_temporary_id"
|
||||||
var selectedItems = [];
|
var selectedItems = [];
|
||||||
|
var token = "";
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * *
|
||||||
* *
|
* *
|
||||||
@ -115,6 +116,7 @@ var deleteEvent = function(event) {
|
|||||||
let request = new XMLHttpRequest();
|
let request = new XMLHttpRequest();
|
||||||
|
|
||||||
request.open('DELETE', link);
|
request.open('DELETE', link);
|
||||||
|
request.setRequestHeader('Token', token);
|
||||||
request.send();
|
request.send();
|
||||||
request.onreadystatechange = function() {
|
request.onreadystatechange = function() {
|
||||||
if (request.readyState == 4) {
|
if (request.readyState == 4) {
|
||||||
@ -165,6 +167,11 @@ var RemoveLastDirectoryPartOf = function(url) {
|
|||||||
return (arr.join('/'));
|
return (arr.join('/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the current token
|
||||||
|
var updateToken = function() {
|
||||||
|
token = document.getElementById("token").innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * *
|
||||||
* *
|
* *
|
||||||
* LISTING SPECIFIC FUNCTIONS *
|
* LISTING SPECIFIC FUNCTIONS *
|
||||||
@ -175,6 +182,7 @@ var reloadListing = function() {
|
|||||||
let request = new XMLHttpRequest();
|
let request = new XMLHttpRequest();
|
||||||
request.open('GET', window.location);
|
request.open('GET', window.location);
|
||||||
request.setRequestHeader('Minimal', 'true');
|
request.setRequestHeader('Minimal', 'true');
|
||||||
|
request.setRequestHeader('Token', token);
|
||||||
request.send();
|
request.send();
|
||||||
request.onreadystatechange = function() {
|
request.onreadystatechange = function() {
|
||||||
if (request.readyState == 4) {
|
if (request.readyState == 4) {
|
||||||
@ -186,6 +194,7 @@ var reloadListing = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename file event
|
// Rename file event
|
||||||
@ -217,6 +226,7 @@ var renameEvent = function(event) {
|
|||||||
let request = new XMLHttpRequest();
|
let request = new XMLHttpRequest();
|
||||||
request.open('PATCH', link);
|
request.open('PATCH', link);
|
||||||
request.setRequestHeader('Rename-To', newName);
|
request.setRequestHeader('Rename-To', newName);
|
||||||
|
request.setRequestHeader('Token', token);
|
||||||
request.send();
|
request.send();
|
||||||
request.onreadystatechange = function() {
|
request.onreadystatechange = function() {
|
||||||
if (request.readyState == 4) {
|
if (request.readyState == 4) {
|
||||||
@ -274,6 +284,7 @@ var handleFiles = function(files) {
|
|||||||
let request = new XMLHttpRequest();
|
let request = new XMLHttpRequest();
|
||||||
request.open('POST', window.location.pathname);
|
request.open('POST', window.location.pathname);
|
||||||
request.setRequestHeader("Upload", "true");
|
request.setRequestHeader("Upload", "true");
|
||||||
|
request.setRequestHeader('Token', token);
|
||||||
request.send(data);
|
request.send(data);
|
||||||
request.onreadystatechange = function() {
|
request.onreadystatechange = function() {
|
||||||
if (request.readyState == 4) {
|
if (request.readyState == 4) {
|
||||||
@ -382,6 +393,7 @@ var newDirEvent = function(event) {
|
|||||||
let html = button.changeToLoading();
|
let html = button.changeToLoading();
|
||||||
let request = new XMLHttpRequest();
|
let request = new XMLHttpRequest();
|
||||||
request.open("POST", window.location);
|
request.open("POST", window.location);
|
||||||
|
request.setRequestHeader('Token', token);
|
||||||
request.setRequestHeader('Filename', document.getElementById('newdir').value);
|
request.setRequestHeader('Filename', document.getElementById('newdir').value);
|
||||||
request.send();
|
request.send();
|
||||||
request.onreadystatechange = function() {
|
request.onreadystatechange = function() {
|
||||||
@ -444,6 +456,7 @@ var searchEvent = function(event) {
|
|||||||
let request = new XMLHttpRequest();
|
let request = new XMLHttpRequest();
|
||||||
request.open('POST', window.location);
|
request.open('POST', window.location);
|
||||||
request.setRequestHeader('Command', value);
|
request.setRequestHeader('Command', value);
|
||||||
|
request.setRequestHeader('Token', token);
|
||||||
request.send();
|
request.send();
|
||||||
request.onreadystatechange = function() {
|
request.onreadystatechange = function() {
|
||||||
if (request.readyState == 4) {
|
if (request.readyState == 4) {
|
||||||
@ -751,6 +764,7 @@ document.addEventListener("editor", (event) => {
|
|||||||
let request = new XMLHttpRequest();
|
let request = new XMLHttpRequest();
|
||||||
request.open("PUT", window.location);
|
request.open("PUT", window.location);
|
||||||
request.setRequestHeader('Kind', kind);
|
request.setRequestHeader('Kind', kind);
|
||||||
|
request.setRequestHeader('Token', token);
|
||||||
request.send(JSON.stringify(data));
|
request.send(JSON.stringify(data));
|
||||||
request.onreadystatechange = function() {
|
request.onreadystatechange = function() {
|
||||||
if (request.readyState == 4) {
|
if (request.readyState == 4) {
|
||||||
@ -781,6 +795,9 @@ document.addEventListener("DOMContentLoaded", function(event) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Updates the token
|
||||||
|
updateToken();
|
||||||
|
|
||||||
// Enables open, delete and download buttons
|
// Enables open, delete and download buttons
|
||||||
document.getElementById("open").addEventListener("click", openEvent);
|
document.getElementById("open").addEventListener("click", openEvent);
|
||||||
document.getElementById("delete").addEventListener("click", deleteEvent);
|
document.getElementById("delete").addEventListener("click", deleteEvent);
|
||||||
|
@ -104,6 +104,7 @@
|
|||||||
|
|
||||||
<main>
|
<main>
|
||||||
{{ template "content" .Data }}
|
{{ template "content" .Data }}
|
||||||
|
<span id="token">{{ .Config.Token }}</span>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
|
@ -1 +1,2 @@
|
|||||||
{{ template "content" .Data }}
|
{{ template "content" .Data }}
|
||||||
|
<span id="token">{{ .Config.Token }}</span>
|
||||||
|
@ -17,6 +17,7 @@ type Config struct {
|
|||||||
BaseURL string
|
BaseURL string
|
||||||
AbsoluteURL string
|
AbsoluteURL string
|
||||||
AddrPath string
|
AddrPath string
|
||||||
|
Token string // Anti CSRF token
|
||||||
StyleSheet string // Costum stylesheet
|
StyleSheet string // Costum stylesheet
|
||||||
FrontMatter string // Default frontmatter to save files in
|
FrontMatter string // Default frontmatter to save files in
|
||||||
HugoEnabled bool // Enables the Hugo plugin for File Manager
|
HugoEnabled bool // Enables the Hugo plugin for File Manager
|
||||||
|
42
config/secure.go
Normal file
42
config/secure.go
Normal file
@ -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
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"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
|
// Route the request depending on the HTTP Method
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodGet:
|
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)
|
return assets.Serve(w, r, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.GenerateToken()
|
||||||
|
fmt.Println(c.Token)
|
||||||
|
|
||||||
if !fi.IsDir {
|
if !fi.IsDir {
|
||||||
query := r.URL.Query()
|
query := r.URL.Query()
|
||||||
if val, ok := query["raw"]; ok && val[0] == "true" {
|
if val, ok := query["raw"]; ok && val[0] == "true" {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user