Issue #32: working live with WebSockets! Needs to be reviewed.
parent
12c76b7a54
commit
44065cfaf9
|
@ -473,8 +473,8 @@ header {
|
|||
z-index: 999;
|
||||
padding: 1.7em 0;
|
||||
background-color: #2196f3;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.075);
|
||||
box-shadow: 0 0 5px rgba(0,0,0,0.1);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.075);
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
header h1 {
|
||||
|
@ -548,7 +548,7 @@ header p i {
|
|||
min-width: 20em;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
color: #fff;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
|
@ -574,14 +574,22 @@ header p i {
|
|||
transition: .1s ease all;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
max-height: 50vh;
|
||||
white-space: pre-wrap;
|
||||
white-space: -moz-pre-wrap;
|
||||
white-space: -pre-wrap;
|
||||
white-space: -o-pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#search.active div i,
|
||||
#sidebar #search.active div i {
|
||||
color: #ccc;
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
display: table;
|
||||
}
|
||||
|
||||
#search::-webkit-input-placeholder {
|
||||
|
|
|
@ -503,29 +503,18 @@ var searchEvent = function(event) {
|
|||
if (event.keyCode == 13) {
|
||||
box.innerHTML = '<i class="material-icons spin">autorenew</i>';
|
||||
|
||||
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) {
|
||||
if (request.status == 501) {
|
||||
box.innerHTML = "Command not implemented."
|
||||
}
|
||||
var conn = new WebSocket('ws://' + window.location.host + window.location.pathname + '?command=true');
|
||||
conn.onopen = function() {
|
||||
conn.send(value);
|
||||
};
|
||||
|
||||
if (request.status == 500) {
|
||||
box.innerHTML = "Something went wrong."
|
||||
}
|
||||
conn.onmessage = function(event) {
|
||||
box.innerHTML = event.data
|
||||
box.scrollTop = box.scrollHeight;
|
||||
}
|
||||
|
||||
if (request.status == 200) {
|
||||
let text = request.responseText;
|
||||
text = text.substring(1, text.length - 1);
|
||||
text = text.replace('\\n', "\n");
|
||||
box.innerHTML = text;
|
||||
reloadListing();
|
||||
}
|
||||
}
|
||||
conn.onclose = function(event) {
|
||||
reloadListing();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -554,13 +543,28 @@ document.addEventListener('listing', event => {
|
|||
});
|
||||
|
||||
if (user.AllowCommands) {
|
||||
let hover = false, focus = false;
|
||||
|
||||
document.querySelector('#search input').addEventListener('focus', event => {
|
||||
focus = true;
|
||||
document.getElementById('search').classList.add('active');
|
||||
});
|
||||
|
||||
document.querySelector('#search div').addEventListener('mouseover', event => {
|
||||
hover = true;
|
||||
document.getElementById('search').classList.add('active');
|
||||
});
|
||||
|
||||
document.querySelector('#search input').addEventListener('blur', event => {
|
||||
focus = false;
|
||||
if (hover) return;
|
||||
document.getElementById('search').classList.remove('active');
|
||||
});
|
||||
|
||||
document.querySelector('#search').addEventListener('mouseleave', event => {
|
||||
hover = false;
|
||||
if (focus) return;
|
||||
document.getElementById('search').classList.remove('active');
|
||||
document.querySelector('#search input').value = '';
|
||||
});
|
||||
|
||||
document.querySelector('#search div').innerHTML = "Write one of yours suported commands: " + user.Commands.join(", ") + ".";
|
||||
|
|
|
@ -42,7 +42,7 @@ func GetInfo(url *url.URL, c *config.Config, u *config.User) (*Info, int, error)
|
|||
|
||||
i.FileInfo, err = os.Stat(i.Path)
|
||||
if err != nil {
|
||||
return i, errors.ErrorToHTTPCode(err, true), err
|
||||
return i, errors.ErrorToHTTPCode(err, false), err
|
||||
}
|
||||
|
||||
return i, 0, nil
|
||||
|
|
|
@ -67,6 +67,16 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
|
|||
user = c.User
|
||||
}
|
||||
|
||||
if r.URL.Query().Get("command") != "" {
|
||||
return handlers.Command(w, r, c, user)
|
||||
}
|
||||
|
||||
// TODO: This anti CSCF measure is not being applied to requests
|
||||
// to the WebDav URL namespace. Anyone has ideas?
|
||||
// if !c.CheckToken(r) {
|
||||
// return http.StatusForbidden, nil
|
||||
// }
|
||||
|
||||
// Checks if the request URL is for the WebDav server
|
||||
if strings.HasPrefix(r.URL.Path, c.WebDavURL) {
|
||||
// if !c.CheckToken(r) {
|
||||
|
@ -126,23 +136,6 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
|
|||
co, err := r.Cookie("token")
|
||||
fmt.Println(co.Value) */
|
||||
|
||||
/* Name string
|
||||
Value string
|
||||
|
||||
Path string // optional
|
||||
Domain string // optional
|
||||
Expires time.Time // optional
|
||||
RawExpires string // for reading cookies only
|
||||
|
||||
// MaxAge=0 means no 'Max-Age' attribute specified.
|
||||
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
|
||||
// MaxAge>0 means Max-Age attribute present and given in seconds
|
||||
MaxAge int
|
||||
Secure bool
|
||||
HttpOnly bool
|
||||
Raw string
|
||||
Unparsed []string // Raw text of unparsed attribute-value pairs*/
|
||||
|
||||
// Gets the information of the directory/file
|
||||
fi, code, err = file.GetInfo(r.URL, c, user)
|
||||
if err != nil {
|
||||
|
@ -178,23 +171,6 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
|
|||
return code, err
|
||||
}
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
// TODO: This anti CSCF measure is not being applied to requests
|
||||
// to the WebDav URL namespace. Anyone has ideas?
|
||||
// if !c.CheckToken(r) {
|
||||
// return http.StatusForbidden, nil
|
||||
// }
|
||||
|
||||
// VCS commands.
|
||||
if r.Header.Get("Command") != "" {
|
||||
if !user.AllowCommands {
|
||||
return http.StatusUnauthorized, nil
|
||||
}
|
||||
|
||||
return handlers.Command(w, r, c, user)
|
||||
}
|
||||
}
|
||||
|
||||
return http.StatusNotImplemented, nil
|
||||
|
||||
}
|
||||
|
|
|
@ -1,18 +1,122 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/hacdias/caddy-filemanager/config"
|
||||
"github.com/hacdias/caddy-filemanager/page"
|
||||
)
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
}
|
||||
|
||||
// Command handles the requests for VCS related commands: git, svn and mercurial
|
||||
func Command(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.User) (int, error) {
|
||||
command := strings.Split(r.Header.Get("command"), " ")
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return 0, nil
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
for {
|
||||
_, message, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
fmt.Println("read:", err)
|
||||
break
|
||||
}
|
||||
|
||||
command := strings.Split(string(message), " ")
|
||||
|
||||
if len(command) == 0 {
|
||||
continue
|
||||
}
|
||||
// Check if the command is allowed
|
||||
mayContinue := false
|
||||
|
||||
for _, cmd := range u.Commands {
|
||||
if cmd == command[0] {
|
||||
mayContinue = true
|
||||
}
|
||||
}
|
||||
|
||||
if !mayContinue {
|
||||
err = conn.WriteMessage(websocket.BinaryMessage, []byte("FORBIDDEN"))
|
||||
if err != nil {
|
||||
fmt.Println("write:", err)
|
||||
break
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Check if the program is talled is installed on the computer
|
||||
if _, err = exec.LookPath(command[0]); err != nil {
|
||||
err = conn.WriteMessage(websocket.BinaryMessage, []byte("Command not implemented."))
|
||||
if err != nil {
|
||||
fmt.Println("write:", err)
|
||||
break
|
||||
}
|
||||
|
||||
return http.StatusNotImplemented, nil
|
||||
}
|
||||
|
||||
path := strings.Replace(r.URL.Path, c.BaseURL, c.Scope, 1)
|
||||
path = filepath.Clean(path)
|
||||
|
||||
buff := new(bytes.Buffer)
|
||||
|
||||
cmd := exec.Command(command[0], command[1:len(command)]...)
|
||||
cmd.Dir = path
|
||||
cmd.Stderr = buff
|
||||
cmd.Stdout = buff
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
done := false
|
||||
go func() {
|
||||
err = cmd.Wait()
|
||||
done = true
|
||||
}()
|
||||
|
||||
for !done {
|
||||
by := buff.Bytes()
|
||||
if len(by) > 0 {
|
||||
err = conn.WriteMessage(websocket.TextMessage, by)
|
||||
if err != nil {
|
||||
fmt.Println("write:", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
by := buff.Bytes()
|
||||
if len(by) > 0 {
|
||||
err = conn.WriteMessage(websocket.TextMessage, by)
|
||||
if err != nil {
|
||||
fmt.Println("write:", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
/* command := strings.Split(r.Header.Get("command"), " ")
|
||||
|
||||
// Check if the command is allowed
|
||||
mayContinue := false
|
||||
|
@ -37,12 +141,44 @@ func Command(w http.ResponseWriter, r *http.Request, c *config.Config, u *config
|
|||
|
||||
cmd := exec.Command(command[0], command[1:len(command)]...)
|
||||
cmd.Dir = path
|
||||
output, err := cmd.CombinedOutput()
|
||||
cmd.Stderr = w
|
||||
cmd.Stdout = w
|
||||
cmd.Start()
|
||||
|
||||
/*cmd.Stderr = b
|
||||
cmd.Stdout = b
|
||||
|
||||
// Starts the comamnd
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
p := &page.Page{Info: &page.Info{Data: string(output)}}
|
||||
return p.PrintAsJSON(w)
|
||||
done := false
|
||||
go func() {
|
||||
err = cmd.Wait()
|
||||
done = true
|
||||
}()
|
||||
|
||||
for !done {
|
||||
by := b.Bytes()
|
||||
if len(by) > 0 {
|
||||
fmt.Println(string(by))
|
||||
}
|
||||
|
||||
//w.Write(by)
|
||||
|
||||
}*/
|
||||
|
||||
//out, err := cmd.CombinedOutput()
|
||||
//fmt.Println(string(out))
|
||||
|
||||
//if err != nil {
|
||||
// return http.StatusInternalServerError, err
|
||||
//}
|
||||
|
||||
/* cmd.Wait()
|
||||
|
||||
//p := &page.Page{Info: &page.Info{Data: string(output)}} */
|
||||
return 0, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue