diff --git a/archetype/fileManager.go b/archetype/fileManager.go index 46a5538..3b4815e 100644 --- a/archetype/fileManager.go +++ b/archetype/fileManager.go @@ -32,11 +32,10 @@ type FileListing struct { type FileManager interface { Init(cfg *Config) error - // ListTree() FileListing ListSubTree(root string) FileListing GetFileData(slug string) FileData AddFile(path string, req *http.Request) error - // MkDir(path string) error + MkDir(path, newDir string) error Remove(path string) error // Rename(old, new string) error } @@ -169,3 +168,27 @@ func (self *SimpleFileManager) AddFile(path string, req *http.Request) error { dest.Write(fileData) return nil } + +func (self *SimpleFileManager) MkDir(path, newDir string) error { + fullPath := filepath.Join(self.Root, path) + if !strings.HasPrefix(fullPath, self.Root) { + return errors.New("You cannot escape!") + } + + _, err := os.Stat(fullPath) + if err != nil { + return err + } + + if strings.Contains(newDir, "/") || strings.Contains(newDir, "\\") { + return errors.New("Cannot create nested directories at once") + } + + newDirPath := filepath.Join(fullPath, newDir) + _, err = os.Stat(newDirPath) + if !os.IsNotExist(err) { + return errors.New("Directory exists") + } + + return os.Mkdir(newDirPath, 0755) +} diff --git a/nirvash.go b/nirvash.go index a54eb05..386dbf0 100644 --- a/nirvash.go +++ b/nirvash.go @@ -292,10 +292,36 @@ func main() { udb, "/"))) + rtr.Get( + `/mkdir/(?P.*)`, + Fortify( + Protected( + WithFileManager( + renderer.Template( + pathConcat(templateRoot, "file_mkdir.html"), + pathConcat(templateRoot, "header.html"), + pathConcat(templateRoot, "footer.html")), + fileManager), + http.MethodGet, + udb, + "/login"))) + + rtr.Post( + `/mkdir-process/(?P.*)`, + Defend( + Protected( + WithFileManager( + renderer.Template( + pathConcat(templateRoot, "file_mkdir_process.html"), + pathConcat(templateRoot, "header.html"), + pathConcat(templateRoot, "footer.html")), + fileManager), + http.MethodGet, + udb, + "/login"), + udb, + "/")) // TODO: - // file upload GET contains form for file upload in current directory - // file upload POST performs the action of creating/overwriting - // add directory GET contains the form for directory creation // add directory POST performs the action of creating directory // move-choose POST uses a form to navigate through the file tree // - to use links to navigate, destination location uses the slug, diff --git a/static/style.css b/static/style.css index 5811059..51acd60 100644 --- a/static/style.css +++ b/static/style.css @@ -180,7 +180,7 @@ h2 { position: relative; } -.page-list, form.editor, form.build, form.configurator, span.adapter-error, span.adapter-success, .file-move, .danger-zone, .uploader { +.page-list, form.editor, form.build, form.configurator, span.adapter-error, span.adapter-success, .file-move, .danger-zone, .uploader, .mkdir { display: block; overflow-x: hidden; width: 80%; @@ -196,13 +196,13 @@ span.adapter-error { border-bottom: 2px solid crimson; } -form.editor label, form.build label, .danger-zone label, form.configurator label, form.file-move label { +form.editor label, form.build label, .danger-zone label, form.configurator label, form.file-move label, .mkdir label { font-size: 80%; color: lightgray; text-transform: uppercase; } -form.editor input, form.build input, form.editor textarea, form.configurator input, form.configurator textarea, .danger-zone input[type="submit"], .file-move input[type="submit"], .uploader label, .uploader input[type="submit"] { +form.editor input, form.build input, form.editor textarea, form.configurator input, form.configurator textarea, .danger-zone input[type="submit"], .file-move input[type="submit"], .uploader label, .uploader input[type="submit"], .mkdir input { display: block; margin: 0; margin-top: 0.2em; @@ -217,16 +217,18 @@ form.editor input, form.build input, form.editor textarea, form.configurator inp } .uploader label { + position:relative; text-transform: uppercase; display: inline-block; transition: background 1s, color 1s; + z-index: 2; } .upload-warning { border-bottom: 2px solid crimson; } -form.editor input[type="text"], form.configurator input[type="text"], form.configurator input[type="number"], form.build input[type="text"] { +form.editor input[type="text"], form.configurator input[type="text"], form.configurator input[type="number"], form.build input[type="text"], .mkdir input[type="text"] { margin: 0; width: 100%; @@ -265,7 +267,7 @@ form.configurator input, form.configurator textarea { font-size: 125%; } -form.editor input[type="submit"], form.build input[type="submit"], .danger-zone input[type="submit"], form.configurator input[type="submit"], .file-move input[type="submit"], .uploader input[type="submit"] { +form.editor input[type="submit"], form.build input[type="submit"], .danger-zone input[type="submit"], form.configurator input[type="submit"], .file-move input[type="submit"], .uploader input[type="submit"], .mkdir input[type="submit"] { margin-left: auto; margin-right: 0; font-size: 150%; @@ -273,7 +275,7 @@ form.editor input[type="submit"], form.build input[type="submit"], .danger-zone transition: background 1s, color 1s; } -form.editor input[type="submit"]:hover,form.build input[type="submit"]:hover, .danger-zone input[type="submit"]:hover, form.configurator input[type="submit"]:hover, .file-move input[type="submit"]:hover, .uploader input[type="submit"]:hover, .uploader label:hover { +form.editor input[type="submit"]:hover,form.build input[type="submit"]:hover, .danger-zone input[type="submit"]:hover, form.configurator input[type="submit"]:hover, .file-move input[type="submit"]:hover, .uploader input[type="submit"]:hover, .uploader label:hover, .mkdir input[type="submit"]:hover { background: lightgray; color: black; } @@ -286,6 +288,7 @@ form.editor input[type="submit"]:hover,form.build input[type="submit"]:hover, .d .page-list ul { margin: 0; + padding: 0; position: relative; list-style: none; z-index: 1; @@ -320,5 +323,31 @@ form input[readonly] { } input[type="file"] { - display: none; -} \ No newline at end of file + opacity: 0; + position: absolute; + z-index: 1; + top: 5px; + height: 50px; + width: 110px; +} + + +input[type="file"]:not(:valid) + .file-feedback::after { + content: "No file selected"; + height: 1em; + display: block; +} + +input[type="file"]:valid + .file-feedback::after { + content: "File selected"; + height: 1em; + display: block; +} + +.file-feedback { + z-index: 2; +} + +.upload-wrapper { + position: relative; +} diff --git a/templates/file_mkdir.html b/templates/file_mkdir.html new file mode 100644 index 0000000..e3758e4 --- /dev/null +++ b/templates/file_mkdir.html @@ -0,0 +1,18 @@ +{{ $slug := ((.Context).Value "params").Slug }} +{{ $csrfToken := (.Context).Value "csrfToken" }} + +{{ template "header" . }} + +

Directory Creation

+ +
+ + Creating new directory in /{{$slug}}
+ + + + + +
+ +{{ template "footer" . }} diff --git a/templates/file_mkdir_process.html b/templates/file_mkdir_process.html new file mode 100644 index 0000000..c891cca --- /dev/null +++ b/templates/file_mkdir_process.html @@ -0,0 +1,15 @@ +{{ $slug := ((.Context).Value "params").Slug }} +{{ $newDir := .FormValue "dirname" }} +{{ $mkdirError := ((.Context).Value "file-manager").MkDir $slug $newDir }} + +{{ template "header" . }} + +{{ if $mkdirError }} +

Directory Creation Error

+ {{($mkdirError).Error}} +{{ else }} +

Directory Created

+ The directory has been created successfully +{{ end }} + +{{ template "footer" . }} \ No newline at end of file diff --git a/templates/file_upload.html b/templates/file_upload.html index 6c80e5d..636f5d4 100644 --- a/templates/file_upload.html +++ b/templates/file_upload.html @@ -1,8 +1,16 @@ {{ $slug := ((.Context).Value "params").Slug }} {{ $csrfToken := (.Context).Value "csrfToken" }} +{{ $fileListing := ((.Context).Value "file-manager").ListSubtree $slug }} {{ template "header" . }} +{{ if ($fileListing).Error }} +

Error

+ +{{($fileListing).Error}} + +{{ else }} +

File Upload

@@ -10,11 +18,14 @@ Uploading file to /{{$slug}}
(file with the same name as your upload will be overwritten!)
- - +
+
+ +
+
-{{ template "footer" . }} \ No newline at end of file +{{ end }} + +{{ template "footer" . }}