mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2024-04-21 12:32:08 +00:00
fix (share): fix edge cases around the path and start migrate tests
This commit is contained in:
@@ -1,48 +0,0 @@
|
||||
const p = require("./path");
|
||||
|
||||
describe("Path", () => {
|
||||
it("can create beautiful with proper convention for folder or file", () => {
|
||||
let res = p.pathBuilder("/test/polo", "polo", "file");
|
||||
expect(res).toBe("/test/polo/polo");
|
||||
|
||||
res = p.pathBuilder("/test/polo", "polo", "directory");
|
||||
expect(res).toBe("/test/polo/polo/");
|
||||
});
|
||||
|
||||
it("can extract the filename from a path", () => {
|
||||
let res = p.basename("/var/www/html/test")
|
||||
expect(res).toBe("test");
|
||||
});
|
||||
|
||||
it("can extract the dirname from a path", () => {
|
||||
let res = p.basename("/var/www/html/test/")
|
||||
expect(res).toBe("test");
|
||||
});
|
||||
|
||||
it("can transform 2 absolute path as relative", () => {
|
||||
let res = p.absoluteToRelative("/var/www/", "/var/www/html/test");
|
||||
expect(res).toBe("./html/test");
|
||||
|
||||
res = p.absoluteToRelative("/var/www/html/test/", "/var/www/polo");
|
||||
expect(res).toBe("../../polo")
|
||||
|
||||
res = p.absoluteToRelative("/var/www/html/test", "/var/www/polo");
|
||||
expect(res).toBe("../polo")
|
||||
|
||||
res = p.absoluteToRelative("/var/www/html/test", "/var/www/polo/");
|
||||
expect(res).toBe("../polo/")
|
||||
|
||||
res = p.absoluteToRelative("/var/www/", "/var/www/html/test/");
|
||||
expect(res).toBe("./html/test/");
|
||||
|
||||
res = p.absoluteToRelative("/var/www/", "/var/www/");
|
||||
expect(res).toBe("./");
|
||||
|
||||
res = p.absoluteToRelative("/var/www", "/var/www/");
|
||||
expect(res).toBe("./www/");
|
||||
|
||||
res = p.absoluteToRelative("/var/test/", "/var/www");
|
||||
expect(res).toBe("../www");
|
||||
});
|
||||
|
||||
});
|
||||
@@ -161,12 +161,12 @@ export class ShareComponent extends React.Component {
|
||||
|
||||
render(){
|
||||
const beautifulPath = function(from, to){
|
||||
to = from.replace(/\/$/, "") + to;
|
||||
if(filetype(from) === "directory"){
|
||||
from = from.split("/");
|
||||
from = from.slice(0, from.length - 1);
|
||||
from = from.join("/");
|
||||
from = from.split("/")
|
||||
from = from.slice(0, from.length - 1)
|
||||
from = from.join("/")
|
||||
}
|
||||
|
||||
let p = absoluteToRelative(from, to);
|
||||
return p.length < to.length ? p : to;
|
||||
};
|
||||
|
||||
@@ -67,7 +67,6 @@ export class ViewerPage extends React.Component {
|
||||
Files.options(this.state.path)
|
||||
]).then((d) => {
|
||||
const [content, options] = d;
|
||||
console.log(options);
|
||||
options.allowed
|
||||
this.setState({
|
||||
content: content,
|
||||
@@ -75,7 +74,6 @@ export class ViewerPage extends React.Component {
|
||||
acl: options["allow"]
|
||||
});
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
if(err && err.code === 'BINARY_FILE'){
|
||||
this.setState({opener: 'download', loading: false});
|
||||
}else{
|
||||
|
||||
@@ -122,13 +122,13 @@ export class IDE extends React.Component {
|
||||
</DropdownButton>
|
||||
<DropdownList>
|
||||
<DropdownItem name="na"><a download={this.props.filename} href={this.props.url}>Save current file</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "me")+"/text/html"+this.props.path}>Export as HTML</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "me")+"/application/pdf"+this.props.path}>Export as PDF</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "me")+"/text/plain"+this.props.path}>Export as Text</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "tex")} href={"/api/export/"+(currentShare() || "me")+"/text/x-latex"+this.props.path}>Export as Latex</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "ics")} href={"/api/export/"+(currentShare() || "me")+"/text/calendar"+this.props.path}>Export as Calendar</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "pdf")} href={"/api/export/"+(currentShare() || "me")+"/application/pdf"+this.props.path+"?mode=beamer"}>Export as Beamer</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "odt")} href={"/api/export/"+(currentShare() || "me")+"/application/vnd.oasis.opendocument.text"+this.props.path}>Export as Open office</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/text/html"+this.props.path}>Export as HTML</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/application/pdf"+this.props.path}>Export as PDF</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/text/plain"+this.props.path}>Export as Text</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "tex")} href={"/api/export/"+(currentShare() || "private")+"/text/x-latex"+this.props.path}>Export as Latex</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "ics")} href={"/api/export/"+(currentShare() || "private")+"/text/calendar"+this.props.path}>Export as Calendar</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "pdf")} href={"/api/export/"+(currentShare() || "private")+"/application/pdf"+this.props.path+"?mode=beamer"}>Export as Beamer</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "odt")} href={"/api/export/"+(currentShare() || "private")+"/application/vnd.oasis.opendocument.text"+this.props.path}>Export as Open office</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "me")+"/text/markdown"+this.props.path}>Export as Markdown</a></DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
(setq org-todo-keywords (quote ((sequence "TODO(t)" "DOING(d)" "WAITING(w)" "|" "CANCEL(C)" "DEFERRED(F)" "DONE(D)"))))
|
||||
|
||||
;; html export
|
||||
(setq org-html-head "<meta http-equiv='X-UA-Compatible' content='IE=edge'><meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'><style>html{touch-action:manipulation;-webkit-text-size-adjust:100%}body{padding:0;margin:0;background:#f2f6fa;color:#3c495a;font-weight:normal;font-size:16px;font-family:'avenir next','avenir','San Francisco','Roboto','Arial',sans-serif}h2,h3,h4,h5,h6{font-family:'Trebuchet MS',Verdana,sans-serif;color:#586b82;padding:0;margin:20px 0 10px 0;font-size:1.2em}h2{margin:30px 0 20px 0;font-size:1.5em}h2:after{display:block;content:' ';width:60px;border-bottom:3px solid #586b82;margin-top:5px;}li{text-align:left;}a{color:#3fa7ba;text-decoration:none}p{margin:10px 0;text-align:justify}ul,ol{margin:0;text-align:justify}#content ul,#content ol{margin-top:-5px;}#content ul>li>ul, #content ol>li>ol{margin-top:0;} ul>li>code{color:#586b82}pre{white-space:pre-wrap}pre.src{padding:10px}#content{width:96%;max-width:950px;margin:2% auto 5% auto;background:white;border-radius:2px;border-right:1px solid #e2e9f0;border-bottom:2px solid #e2e9f0;padding:0 115px 150px 115px;box-sizing:border-box}.org-src-container{margin-top:50px}#postamble{opacity:0.5;padding-bottom:10px;}#postamble .author{display:none}#postamble p{text-align:center;}h1.title{background-color:#343C44;color:#fff;margin:0 -115px 50px -115px;padding:60px 0;font-weight:normal;font-size:2em;border-top-left-radius:2px;border-top-right-radius:2px}@media (max-width: 1050px){#content{padding:0 70px 100px 70px}h1.title{margin:0 -70px 50px -70px}}@media (max-width: 800px){#content{width:100%;margin-top:0;padding:0 4% 60px 4%}h1.title{margin:0 -5% 50px -5%;padding:40px 5%}}pre,.verse{box-shadow:none;background-color:#f9fbfd;border:1px solid #e2e9f0;color:#586b82;padding:10px;font-family:monospace;overflow:auto;margin:6px 0}#table-of-contents{margin-bottom:50px;margin-top:50px}#table-of-contents h2{margin-bottom:15px}#text-table-of-contents ul{padding-left:15px}#text-table-of-contents>ul{padding-left:0}#text-table-of-contents li{list-style-type:none}#text-table-of-contents a{color:#7c8ca1;font-size:0.95em;text-decoration:none}table{border-color:#586b82;font-size:0.95em}table thead{color:#586b82}table tbody tr:nth-child(even){background:#f9f9f9}table tbody tr:hover{background:#586b82!important;color:white}table .left{text-align:left}table .right{text-align:right}.todo{font-family:inherit;color:inherit}.done{color:inherit}.tag{background:initial}.tag>span{background-color:#eee;font-family:monospace;padding-left:7px;padding-right:7px;border-radius:2px;float:right;margin-left:5px;font-size:14px;padding-bottom:2px;}#text-table-of-contents .tag>span{float:none;margin-left:0}.timestamp{color:#7c8ca1}@media print{@page{margin-bottom:3cm;margin-top:3cm;margin-left:2cm;margin-right:2cm;font-size:10px}#content{border:none}}</style>")
|
||||
(setq org-html-head "<meta http-equiv='X-UA-Compatible' content='IE=edge'><meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'><style>html{touch-action:manipulation;-webkit-text-size-adjust:100%}body{padding:0;margin:0;background:#f2f6fa;color:#3c495a;font-weight:normal;font-size:16px;font-family:'avenir next','avenir','San Francisco','Roboto','Arial',sans-serif}h2,h3,h4,h5,h6{font-family:'Trebuchet MS',Verdana,sans-serif;color:#586b82;padding:0;margin:20px 0 10px 0;font-size:1.2em}h2{margin:30px 0 20px 0;font-size:1.5em}h2:after{display:block;content:' ';width:60px;border-bottom:3px solid #586b82;margin-top:5px;}li{text-align:left;}a{color:#3fa7ba;text-decoration:none}p{margin:10px 0;text-align:justify}ul,ol{margin:0;text-align:justify}#content ul,#content ol{margin-top:-5px;}#content ul>li>ul, #content ol>li>ol{margin-top:0;} ul>li>code{color:#586b82}pre{white-space:pre-wrap}pre.src{padding:10px}#content{width:96%;max-width:950px;margin:2% auto 5% auto;background:white;border-radius:2px;border-right:1px solid #e2e9f0;border-bottom:2px solid #e2e9f0;padding:0 115px 150px 115px;box-sizing:border-box}.org-src-container{margin-top:50px}#postamble{opacity:0.5;padding-bottom:10px;}#postamble .author{display:none}#postamble p{text-align:center;}h1.title{background-color:#343C44;color:#fff;margin:0 -115px 50px -115px;padding:60px 0;font-weight:normal;font-size:2em;border-top-left-radius:2px;border-top-right-radius:2px}@media (max-width: 1050px){#content{padding:0 70px 100px 70px}h1.title{margin:0 -70px 50px -70px}}@media (max-width: 800px){#content{width:100%;margin-top:0;padding:0 4% 60px 4%}h1.title{margin:0 -5% 50px -5%;padding:40px 5%}}pre,.verse{box-shadow:none;background-color:#f9fbfd;border:1px solid #e2e9f0;color:#586b82;padding:10px;font-family:monospace;overflow:auto;margin:6px 0}#table-of-contents{margin-bottom:50px;margin-top:50px}#table-of-contents h2{margin-bottom:15px}#text-table-of-contents ul{padding-left:15px}#text-table-of-contents>ul{padding-left:0}#text-table-of-contents li{list-style-type:none}#text-table-of-contents a{color:#7c8ca1;font-size:0.95em;text-decoration:none}table{border-color:#586b82;font-size:0.95em}table thead{color:#586b82}table tbody tr:nth-child(even){background:#f9f9f9}table tbody tr:hover{background:#586b82!important;color:white}table .left{text-align:left}table .right{text-align:right}.todo{font-family:inherit;color:#f26d6d;opacity:0.8}.done{color:inherit}.tag{background:initial}.tag>span{background-color:#eee;font-family:monospace;padding-left:7px;padding-right:7px;border-radius:2px;float:right;margin-left:5px;font-size:14px;padding-bottom:2px;}#text-table-of-contents .tag>span{float:none;margin-left:0}.timestamp{color:#7c8ca1}@media print{@page{margin-bottom:3cm;margin-top:3cm;margin-left:2cm;margin-right:2cm;font-size:10px}#content{border:none}}</style>")
|
||||
(setq org-html-validation-link nil)
|
||||
(setq org-html-creator-string "Using <a href=\"http://filestash.app\">Filestash</a>")
|
||||
|
||||
|
||||
@@ -263,9 +263,7 @@ func JsonIterator(json string) []JSONIterator {
|
||||
} else if value.IsArray() {
|
||||
return true
|
||||
}
|
||||
if value.Value != nil {
|
||||
j = append(j, JSONIterator{k, value.Value()})
|
||||
}
|
||||
j = append(j, JSONIterator{k, value.Value()})
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestConfigGet(t *testing.T) {
|
||||
c := NewConfiguration()
|
||||
assert.Equal(t, nil, c.Get("foo").Interface())
|
||||
assert.Equal(t, nil, c.Get("foo.bar").Interface())
|
||||
}
|
||||
|
||||
func TestConfigDefault(t *testing.T) {
|
||||
c := NewConfiguration()
|
||||
assert.Equal(t, "test", c.Get("foo.bar").Default("test").Interface())
|
||||
assert.Equal(t, "test", c.Get("foo.bar").Default("test").String())
|
||||
assert.Equal(t, "test", c.Get("foo.bar").String())
|
||||
assert.Equal(t, "test", c.Get("foo.bar").Default("nope").String())
|
||||
assert.Equal(t, "nope", c.Get("foo.bar.test").Default("nope").String())
|
||||
}
|
||||
|
||||
func TestConfigTypeCase(t *testing.T) {
|
||||
c := NewConfiguration()
|
||||
assert.Equal(t, nil, c.Get("foo.bar.nil").Default(nil).Interface())
|
||||
assert.Equal(t, true, c.Get("foo.bar.bool").Default(true).Bool())
|
||||
assert.Equal(t, 100, c.Get("foo.bar.int").Default(100).Int())
|
||||
assert.Equal(t, "test", c.Get("foo.bar.string").Default("test").String())
|
||||
}
|
||||
|
||||
func TestConfigSet(t *testing.T) {
|
||||
assert.Equal(t, "test", Config.Get("foo.bar").Set("test").String())
|
||||
assert.Equal(t, "valu", Config.Get("foo.bar").Set("valu").String())
|
||||
assert.Equal(t, "valu", Config.Get("foo.bar.test.bar.foo").Set("valu").String())
|
||||
}
|
||||
|
||||
func BenchmarkGetConfigElement(b *testing.B) {
|
||||
c := NewConfiguration()
|
||||
c.Get("foo.bar.test.foo").Set("test")
|
||||
c.Get("foo.bar.test.bar.foo").Set("valu")
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
c.Get("foo.bar.test.foo").String()
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEncryptString(t *testing.T) {
|
||||
key := "test|test|test|test|test"
|
||||
text := "I'm some text"
|
||||
a, err := EncryptString(key, text)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, a)
|
||||
assert.NotEqual(t, a, text)
|
||||
|
||||
b, err := DecryptString(key, a)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, b, text)
|
||||
|
||||
}
|
||||
|
||||
func TestIDGeneration(t *testing.T) {
|
||||
session := make(map[string]string)
|
||||
session["foo"] = "bar"
|
||||
app := &App{
|
||||
Session: session,
|
||||
}
|
||||
|
||||
id1 := GenerateID(app)
|
||||
session["user"] = "polo"
|
||||
id2 := GenerateID(app)
|
||||
session["doesn_t_matter"] = "N/A"
|
||||
id3 := GenerateID(app)
|
||||
|
||||
assert.NotEqual(t, id1, id2)
|
||||
assert.Equal(t, id2, id3)
|
||||
}
|
||||
|
||||
func TestStringGeneration(t *testing.T) {
|
||||
str := QuickString(10)
|
||||
str1 := QuickString(16)
|
||||
str2 := QuickString(24)
|
||||
assert.Equal(t, len(str), 10)
|
||||
assert.Equal(t, len(str1), 16)
|
||||
assert.Equal(t, len(str2), 24)
|
||||
}
|
||||
+19
-5
@@ -16,17 +16,31 @@ func GetAbsolutePath(p string) string {
|
||||
}
|
||||
|
||||
func IsDirectory(path string) bool {
|
||||
if string(path[len(path)-1]) != "/" {
|
||||
if path == "" {
|
||||
return false
|
||||
}
|
||||
if path[len(path) - 1:] != "/" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func JoinPath(base, file string) (string, error) {
|
||||
/*
|
||||
* Join 2 path together, result has a file
|
||||
*/
|
||||
func JoinPath(base, file string) string {
|
||||
filePath := filepath.Join(base, file)
|
||||
|
||||
if strings.HasPrefix(filePath, base) == false {
|
||||
return "", ErrNotValid
|
||||
return base
|
||||
}
|
||||
return filePath, nil
|
||||
return filePath
|
||||
}
|
||||
|
||||
func EnforceDirectory(path string) string {
|
||||
if path == "" {
|
||||
return "/"
|
||||
} else if path[len(path) - 1:] == "/" {
|
||||
return path
|
||||
}
|
||||
return path + "/"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package common
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func NewBool(t bool) *bool {
|
||||
@@ -66,3 +67,30 @@ func PrettyPrint(json_dirty []byte) []byte {
|
||||
json_pretty.Write([]byte("\n"))
|
||||
return json_pretty.Bytes()
|
||||
}
|
||||
|
||||
type SafeMapStringString struct {
|
||||
sync.RWMutex
|
||||
internal map[string]string
|
||||
}
|
||||
|
||||
func NewSafeMapStringString() SafeMapStringString {
|
||||
return SafeMapStringString{
|
||||
internal: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func(this SafeMapStringString) Set(key string, value string) {
|
||||
this.Lock()
|
||||
this.internal[key] = value
|
||||
this.Unlock()
|
||||
}
|
||||
|
||||
func(this SafeMapStringString) Gets(keys ...string) []string{
|
||||
this.RLock()
|
||||
defer this.RUnlock()
|
||||
res := make([]string, len(keys))
|
||||
for i, key := range keys {
|
||||
res[i] = this.internal[key]
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ctrl
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@@ -91,7 +92,7 @@ func PrivateConfigUpdateHandler(ctx App, res http.ResponseWriter, req *http.Requ
|
||||
func PublicConfigHandler(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
cfg := Config.Export()
|
||||
|
||||
if c, err := Config.MarshalJSON(); err == nil {
|
||||
if c, err := json.Marshal(cfg); err == nil {
|
||||
hash := Hash(string(c))
|
||||
if req.Header.Get("If-None-Match") == hash {
|
||||
res.WriteHeader(http.StatusNotModified)
|
||||
|
||||
@@ -21,6 +21,12 @@ func init() {
|
||||
os.MkdirAll(EXPORT_PATH, os.ModePerm)
|
||||
}
|
||||
func FileExport(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
http.SetCookie(res, &http.Cookie{
|
||||
Name: "download",
|
||||
Value: "",
|
||||
MaxAge: -1,
|
||||
Path: "/",
|
||||
})
|
||||
query := req.URL.Query()
|
||||
p := mux.Vars(req)
|
||||
mimeType := fmt.Sprintf("%s/%s", p["mtype0"], p["mtype1"])
|
||||
@@ -32,12 +38,6 @@ func FileExport(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
SendErrorResult(res, ErrPermissionDenied)
|
||||
return
|
||||
}
|
||||
http.SetCookie(res, &http.Cookie{
|
||||
Name: "download",
|
||||
Value: "",
|
||||
MaxAge: -1,
|
||||
Path: "/",
|
||||
})
|
||||
|
||||
var tmpPath string = EXPORT_PATH + "/export_" + QuickString(10)
|
||||
var cmd *exec.Cmd
|
||||
|
||||
@@ -37,6 +37,7 @@ func SessionGet(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
func SessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
ctx.Body["timestamp"] = time.Now().String()
|
||||
session := model.MapStringInterfaceToMapStringString(ctx.Body)
|
||||
session["path"] = EnforceDirectory(session["path"])
|
||||
|
||||
backend, err := model.NewBackend(&ctx, session)
|
||||
if err != nil {
|
||||
@@ -60,9 +61,9 @@ func SessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
home, err := model.GetHome(backend, ctx.Session["path"])
|
||||
home, err := model.GetHome(backend, session["path"])
|
||||
if err != nil {
|
||||
SendErrorResult(res, err)
|
||||
SendErrorResult(res, ErrInvalidPassword)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -88,8 +89,6 @@ func SessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
|
||||
if home == "" {
|
||||
SendSuccessResult(res, nil)
|
||||
} else if ctx.Body["path"] != nil {
|
||||
SendSuccessResult(res, nil)
|
||||
} else {
|
||||
SendSuccessResult(res, home)
|
||||
}
|
||||
|
||||
+16
-2
@@ -11,20 +11,34 @@ import (
|
||||
)
|
||||
|
||||
func ShareList(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
path, err := pathBuilder(ctx, req.URL.Query().Get("path"))
|
||||
if err != nil {
|
||||
SendErrorResult(res, err)
|
||||
return
|
||||
}
|
||||
listOfSharedLinks, err := model.ShareList(
|
||||
GenerateID(&ctx),
|
||||
req.URL.Query().Get("path"),
|
||||
path,
|
||||
)
|
||||
if err != nil {
|
||||
SendErrorResult(res, err)
|
||||
return
|
||||
}
|
||||
|
||||
for i:=0; i<len(listOfSharedLinks); i++ {
|
||||
listOfSharedLinks[i].Path = "/" + strings.TrimPrefix(listOfSharedLinks[i].Path, path)
|
||||
}
|
||||
SendSuccessResults(res, listOfSharedLinks)
|
||||
}
|
||||
|
||||
func ShareUpsert(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
share_id := mux.Vars(req)["share"]
|
||||
if share_id == "private" {
|
||||
SendErrorResult(res, ErrNotValid)
|
||||
return
|
||||
}
|
||||
s := Share{
|
||||
Id: mux.Vars(req)["share"],
|
||||
Id: share_id,
|
||||
Auth: func() string {
|
||||
if ctx.Share.Id == "" {
|
||||
a, err := req.Cookie(COOKIE_NAME_AUTH)
|
||||
|
||||
+22
-19
@@ -12,22 +12,16 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var ETAGS map[string]string = make(map[string]string)
|
||||
var ETAGS SafeMapStringString = NewSafeMapStringString()
|
||||
|
||||
func StaticHandler(_path string) func(App, http.ResponseWriter, *http.Request) {
|
||||
return func(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
var srcPath string
|
||||
var err error
|
||||
|
||||
if srcPath, err = JoinPath(GetAbsolutePath(_path), req.URL.Path); err != nil {
|
||||
base := GetAbsolutePath(_path)
|
||||
if srcPath = JoinPath(base, req.URL.Path); srcPath == base {
|
||||
http.NotFound(res, req)
|
||||
return
|
||||
}
|
||||
if strings.HasPrefix(_path, "/") == true {
|
||||
http.NotFound(res, req)
|
||||
return
|
||||
}
|
||||
|
||||
ServeFile(res, req, srcPath)
|
||||
}
|
||||
}
|
||||
@@ -38,7 +32,6 @@ func IndexHandler(_path string) func(App, http.ResponseWriter, *http.Request) {
|
||||
http.Redirect(res, req, URL_SETUP, http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
|
||||
srcPath := GetAbsolutePath(_path)
|
||||
ServeFile(res, req, srcPath)
|
||||
}
|
||||
@@ -109,24 +102,31 @@ func hashFile (path string, n int) string {
|
||||
|
||||
func ServeFile(res http.ResponseWriter, req *http.Request, filePath string) {
|
||||
zFilePath := filePath + ".gz"
|
||||
tags := ETAGS.Gets(filePath, zFilePath)
|
||||
etagNormal := tags[0]
|
||||
etagGzip := tags[1]
|
||||
|
||||
if req.Header.Get("If-None-Match") != "" {
|
||||
if req.Header.Get("If-None-Match") == ETAGS[filePath] {
|
||||
browserTag := req.Header.Get("If-None-Match")
|
||||
if browserTag == etagNormal {
|
||||
res.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
} else if req.Header.Get("If-None-Match") == ETAGS[zFilePath] {
|
||||
} else if browserTag == etagGzip {
|
||||
res.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
}
|
||||
head := res.Header()
|
||||
|
||||
if strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") {
|
||||
if file, err := os.OpenFile(zFilePath, os.O_RDONLY, os.ModePerm); err == nil {
|
||||
head.Set("Content-Encoding", "gzip")
|
||||
if ETAGS[zFilePath] == "" {
|
||||
ETAGS[zFilePath] = hashFile(zFilePath, 10)
|
||||
if etagGzip == "" {
|
||||
tag := hashFile(zFilePath, 10)
|
||||
ETAGS.Set(zFilePath, tag)
|
||||
head.Set("Etag", tag)
|
||||
} else {
|
||||
head.Set("Etag", etagGzip)
|
||||
}
|
||||
head.Set("Etag", ETAGS[zFilePath])
|
||||
io.Copy(res, file)
|
||||
return
|
||||
}
|
||||
@@ -137,9 +137,12 @@ func ServeFile(res http.ResponseWriter, req *http.Request, filePath string) {
|
||||
http.NotFound(res, req)
|
||||
return
|
||||
}
|
||||
if ETAGS[filePath] == "" {
|
||||
ETAGS[filePath] = hashFile(filePath, 10)
|
||||
if etagNormal == "" {
|
||||
tag := hashFile(filePath, 10)
|
||||
ETAGS.Set(filePath, tag)
|
||||
head.Set("Etag", tag)
|
||||
} else {
|
||||
head.Set("Etag", etagNormal)
|
||||
}
|
||||
head.Set("Etag", ETAGS[filePath])
|
||||
io.Copy(res, file)
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ func Init(a *App) {
|
||||
middlewares = []Middleware{ IndexHeaders }
|
||||
r.PathPrefix("/admin").Handler(http.HandlerFunc(NewMiddlewareChain(IndexHandler(FILE_INDEX), middlewares, *a))).Methods("GET")
|
||||
|
||||
|
||||
// API for File management
|
||||
files := r.PathPrefix("/api/files").Subrouter()
|
||||
middlewares = []Middleware{ ApiHeaders, SecureHeaders, SessionStart, LoggedInOnly }
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/mickael-kerjean/filestash/server/model"
|
||||
"github.com/gorilla/mux"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -73,6 +74,10 @@ func RedirectSharedLoginIfNeeded(fn func(App, http.ResponseWriter, *http.Request
|
||||
return func(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
share_id := _extractShareId(req)
|
||||
if share_id == "" {
|
||||
if mux.Vars(req)["share"] == "private" {
|
||||
fn(ctx, res, req)
|
||||
return
|
||||
}
|
||||
SendErrorResult(res, ErrNotValid)
|
||||
return
|
||||
}
|
||||
@@ -108,6 +113,7 @@ func CanManageShare(fn func(App, http.ResponseWriter, *http.Request)) func(ctx A
|
||||
// In a scenario where the shared link has already been atributed, we need to make sure
|
||||
// the user that's currently logged in can manage the link. 2 scenarios here:
|
||||
// 1) scenario 1: the user is the very same one that generated the shared link in the first place
|
||||
ctx.Share = Share{}
|
||||
if ctx.Session, err = _extractSession(req, &ctx); err != nil {
|
||||
SendErrorResult(res, err)
|
||||
return
|
||||
@@ -144,7 +150,7 @@ func _extractShareId(req *http.Request) string {
|
||||
return share
|
||||
}
|
||||
m := mux.Vars(req)["share"]
|
||||
if m == "me" {
|
||||
if m == "private" {
|
||||
return ""
|
||||
}
|
||||
return m
|
||||
@@ -156,7 +162,6 @@ func _extractShare(req *http.Request) (Share, error) {
|
||||
if share_id == "" {
|
||||
return Share{}, nil
|
||||
}
|
||||
|
||||
if Config.Get("features.share.enable").Bool() == false {
|
||||
Log.Debug("Share feature isn't enable, contact your administrator")
|
||||
return Share{}, NewError("Feature isn't enable, contact your administrator", 405)
|
||||
@@ -182,37 +187,43 @@ func _extractShare(req *http.Request) (Share, error) {
|
||||
func _extractSession(req *http.Request, ctx *App) (map[string]string, error) {
|
||||
var str string
|
||||
var err error
|
||||
var res map[string]string = make(map[string]string)
|
||||
var session map[string]string = make(map[string]string)
|
||||
|
||||
if ctx.Share.Id != "" {
|
||||
str, err = DecryptString(SECRET_KEY, ctx.Share.Auth)
|
||||
if err != nil {
|
||||
// This typically happen when changing the secret key
|
||||
return res, nil
|
||||
return session, nil
|
||||
}
|
||||
err = json.Unmarshal([]byte(str), &res)
|
||||
if ctx.Share.Path[len(ctx.Share.Path)-1:] == "/" {
|
||||
res["path"] = ctx.Share.Path
|
||||
err = json.Unmarshal([]byte(str), &session)
|
||||
if IsDirectory(ctx.Share.Path) {
|
||||
session["path"] = ctx.Share.Path
|
||||
} else {
|
||||
path := req.URL.Query().Get("path")
|
||||
if strings.HasSuffix(ctx.Share.Path, path) == false {
|
||||
return res, ErrPermissionDenied
|
||||
// when the shared link is pointing to a file, we mustn't have access to the surroundings
|
||||
// => we need to take extra care of which path to use as a chroot
|
||||
var path string = req.URL.Query().Get("path")
|
||||
if strings.HasPrefix(req.URL.Path, "/api/export/") == true {
|
||||
var re = regexp.MustCompile(`^/api/export/[^\/]+/[^\/]+/[^\/]+(\/.+)$`)
|
||||
path = re.ReplaceAllString(req.URL.Path, `$1`)
|
||||
}
|
||||
res["path"] = strings.TrimSuffix(ctx.Share.Path, path) + "/"
|
||||
if strings.HasSuffix(ctx.Share.Path, path) == false {
|
||||
return make(map[string]string), ErrPermissionDenied
|
||||
}
|
||||
session["path"] = strings.TrimSuffix(ctx.Share.Path, path) + "/"
|
||||
}
|
||||
return res, err
|
||||
return session, err
|
||||
} else {
|
||||
cookie, err := req.Cookie(COOKIE_NAME_AUTH)
|
||||
if err != nil {
|
||||
return res, nil
|
||||
return session, nil
|
||||
}
|
||||
str = cookie.Value
|
||||
str, err = DecryptString(SECRET_KEY, str)
|
||||
if err != nil {
|
||||
// This typically happen when changing the secret key
|
||||
return res, nil
|
||||
return session, nil
|
||||
}
|
||||
err = json.Unmarshal([]byte(str), &res)
|
||||
return res, err
|
||||
err = json.Unmarshal([]byte(str), &session)
|
||||
return session, err
|
||||
}
|
||||
}
|
||||
|
||||
+10
-6
@@ -47,21 +47,25 @@ func NewBackend(ctx *App, conn map[string]string) (IBackend, error) {
|
||||
}
|
||||
|
||||
func GetHome(b IBackend, base string) (string, error) {
|
||||
if _, err := b.Ls(base); err != nil {
|
||||
return base, err
|
||||
}
|
||||
|
||||
if obj, ok := b.(interface{ Home() (string, error) }); ok {
|
||||
absolute, err := obj.Home()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if strings.HasPrefix(absolute, base) == false {
|
||||
return "", nil
|
||||
absolute = EnforceDirectory(absolute)
|
||||
base = EnforceDirectory(base)
|
||||
if strings.HasPrefix(absolute, base) {
|
||||
return "/" + absolute[len(base):], nil
|
||||
}
|
||||
return absolute[len(base):], nil
|
||||
return "/", nil
|
||||
}
|
||||
_, err := b.Ls("/")
|
||||
return base, err
|
||||
return base, nil
|
||||
}
|
||||
|
||||
|
||||
func MapStringInterfaceToMapStringString(m map[string]interface{}) map[string]string {
|
||||
res := make(map[string]string)
|
||||
for key, value := range m {
|
||||
|
||||
@@ -1,250 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var app *App
|
||||
|
||||
func init() {
|
||||
app = &App{}
|
||||
}
|
||||
|
||||
// func TestWebdav(t *testing.T) {
|
||||
// if os.Getenv("WEBDAV_URL") == "" {
|
||||
// fmt.Println("- skipped webdav")
|
||||
// return
|
||||
// }
|
||||
// b, err := NewBackend(&App{}, map[string]string{
|
||||
// "type": "webdav",
|
||||
// "url": os.Getenv("WEBDAV_URL"),
|
||||
// })
|
||||
// if err != nil {
|
||||
// t.Errorf("Can't create WebDav backend")
|
||||
// }
|
||||
// setup(t, b)
|
||||
// suite(t, b)
|
||||
// tearDown(t, b)
|
||||
// }
|
||||
|
||||
// func TestFtp(t *testing.T) {
|
||||
// if os.Getenv("FTP_USERNAME") == "" || os.Getenv("FTP_PASSWORD") == "" {
|
||||
// fmt.Println("- skipped ftp")
|
||||
// return
|
||||
// }
|
||||
// b, err := NewBackend(&App{}, map[string]string{
|
||||
// "type": "ftp",
|
||||
// "hostname": "127.0.0.1",
|
||||
// "username": os.Getenv("FTP_USERNAME"),
|
||||
// "password": os.Getenv("FTP_PASSWORD"),
|
||||
// })
|
||||
// if err != nil {
|
||||
// t.Errorf("Can't create FTP backend")
|
||||
// }
|
||||
// setup(t, b)
|
||||
// suite(t, b)
|
||||
// tearDown(t, b)
|
||||
// b.Rm("/tmp/")
|
||||
// }
|
||||
|
||||
// func TestSFtp(t *testing.T) {
|
||||
// if os.Getenv("SFTP_USERNAME") == "" || os.Getenv("SFTP_PASSWORD") == "" {
|
||||
// fmt.Println("- skipped sftp")
|
||||
// return
|
||||
// }
|
||||
// b, err := NewBackend(&App{}, map[string]string{
|
||||
// "type": "sftp",
|
||||
// "hostname": "127.0.0.1",
|
||||
// "username": os.Getenv("SFTP_USERNAME"),
|
||||
// "password": os.Getenv("SFTP_PASSWORD"),
|
||||
// })
|
||||
// if err != nil {
|
||||
// t.Errorf("Can't create SFTP backend")
|
||||
// }
|
||||
// setup(t, b)
|
||||
// suite(t, b)
|
||||
// tearDown(t, b)
|
||||
// }
|
||||
|
||||
// func TestGit(t *testing.T) {
|
||||
// if os.Getenv("GIT_USERNAME") == "" || os.Getenv("GIT_PASSWORD") == "" {
|
||||
// fmt.Println("- skipped git")
|
||||
// return
|
||||
// }
|
||||
// b, err := NewBackend(app, map[string]string{
|
||||
// "type": "git",
|
||||
// "repo": "https://github.com/mickael-kerjean/tmp",
|
||||
// "username": os.Getenv("GIT_EMAIL"),
|
||||
// "password": os.Getenv("GIT_PASSWORD"),
|
||||
// })
|
||||
// if err != nil {
|
||||
// t.Errorf("Can't create Git backend")
|
||||
// }
|
||||
// setup(t, b)
|
||||
// suite(t, b)
|
||||
// tearDown(t, b)
|
||||
// }
|
||||
|
||||
// func TestS3(t *testing.T) {
|
||||
// b, err := NewBackend(&App{}, map[string]string{
|
||||
// "type": "s3",
|
||||
// "access_key_id": "Q3AM3UQ867SPQQA43P2F",
|
||||
// "secret_access_key": "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG",
|
||||
// "endpoint": "https://play.minio.io:9000/",
|
||||
// })
|
||||
// if err != nil {
|
||||
// t.Errorf("Can't create S3 backend")
|
||||
// }
|
||||
// setup(t, b)
|
||||
// // suite(t, b)
|
||||
// //tearDown(t, b)
|
||||
// }
|
||||
|
||||
// func TestDropbox(t *testing.T) {
|
||||
// if os.Getenv("DROPBOX_TOKEN") == "" {
|
||||
// fmt.Println("- skipped Dropbox")
|
||||
// return
|
||||
// }
|
||||
// b, err := NewBackend(app, map[string]string{
|
||||
// "type": "dropbox",
|
||||
// "bearer": os.Getenv("DROPBOX_TOKEN"),
|
||||
// })
|
||||
// if err != nil {
|
||||
// t.Errorf("Can't create a Dropbox backend")
|
||||
// }
|
||||
// setup(t, b)
|
||||
// suite(t, b)
|
||||
// tearDown(t, b)
|
||||
// }
|
||||
|
||||
// func TestGoogleDrive(t *testing.T) {
|
||||
// if os.Getenv("GDRIVE_TOKEN") == "" {
|
||||
// fmt.Println("- skipped Google Drive")
|
||||
// return
|
||||
// }
|
||||
// b, err := NewBackend(app, map[string]string{
|
||||
// "type": "gdrive",
|
||||
// "expiry": "",
|
||||
// "token": os.Getenv("GDRIVE_TOKEN"),
|
||||
// })
|
||||
// if err != nil {
|
||||
// t.Errorf("Can't create a Google Drive backend")
|
||||
// }
|
||||
// setup(t, b)
|
||||
// suite(t, b)
|
||||
// tearDown(t, b)
|
||||
// }
|
||||
|
||||
func setup(t *testing.T, b IBackend) {
|
||||
b.Rm("/tmp/test/")
|
||||
b.Mkdir("/tmp/")
|
||||
b.Mkdir("/tmp/test/")
|
||||
}
|
||||
func tearDown(t *testing.T, b IBackend) {
|
||||
b.Rm("/tmp/test/")
|
||||
}
|
||||
|
||||
func suite(t *testing.T, b IBackend) {
|
||||
// create state
|
||||
content := "lorem ipsum"
|
||||
b.Mkdir("/tmp/test/trash/")
|
||||
b.Touch("/tmp/test/test0.txt")
|
||||
b.Save("/tmp/test/test0.txt", strings.NewReader(content))
|
||||
b.Save("/tmp/test/test1.txt", strings.NewReader(content))
|
||||
b.Touch("/tmp/test/test2.txt")
|
||||
b.Mv("/tmp/test/test0.txt", "/tmp/test/trash/test0.txt")
|
||||
|
||||
// list all files
|
||||
tmp0, err := b.Ls("/tmp/test/")
|
||||
if err != nil {
|
||||
t.Errorf("Ls error: %s", err)
|
||||
return
|
||||
}
|
||||
if len(tmp0) != 3 {
|
||||
t.Errorf("LS error: got: %d elmnt, want: %d", len(tmp0), 3)
|
||||
return
|
||||
}
|
||||
|
||||
// read file
|
||||
tmp1, err := b.Cat("/tmp/test/trash/test0.txt")
|
||||
if err != nil {
|
||||
t.Errorf("Cat error: %s", err)
|
||||
return
|
||||
}
|
||||
tmp2, err := ioutil.ReadAll(tmp1)
|
||||
if err != nil {
|
||||
t.Errorf("Cat error: %s", err)
|
||||
return
|
||||
}
|
||||
if string(tmp2) != content {
|
||||
t.Errorf("Incorrect file: %s, want: %s.", tmp2, content)
|
||||
return
|
||||
}
|
||||
if obj, ok := tmp1.(interface{ Close() error }); ok {
|
||||
obj.Close()
|
||||
}
|
||||
tmp1, err = b.Cat("/tmp/test/test1.txt")
|
||||
if err != nil {
|
||||
t.Errorf("Cat error: %s", err)
|
||||
return
|
||||
}
|
||||
tmp2, err = ioutil.ReadAll(tmp1)
|
||||
if err != nil {
|
||||
t.Errorf("Cat error: %s", err)
|
||||
return
|
||||
}
|
||||
if string(tmp2) != content {
|
||||
t.Errorf("Incorrect file: %s, want: %s.", tmp2, content)
|
||||
return
|
||||
}
|
||||
if obj, ok := tmp1.(interface{ Close() error }); ok {
|
||||
obj.Close()
|
||||
}
|
||||
|
||||
tmp1, err = b.Cat("/tmp/test/test2.txt")
|
||||
if err != nil {
|
||||
t.Errorf("Cat error: %s", err)
|
||||
return
|
||||
}
|
||||
tmp2, err = ioutil.ReadAll(tmp1)
|
||||
if err != nil {
|
||||
t.Errorf("Cat error: %s", err)
|
||||
return
|
||||
}
|
||||
if string(tmp2) != "" {
|
||||
t.Errorf("Incorrect file: %s, want: %s.", tmp2, "")
|
||||
return
|
||||
}
|
||||
if obj, ok := tmp1.(interface{ Close() error }); ok {
|
||||
obj.Close()
|
||||
}
|
||||
|
||||
// remove file
|
||||
b.Rm("/tmp/test/test2.txt")
|
||||
tmp0, err = b.Ls("/tmp/test/")
|
||||
if len(tmp0) != 2 {
|
||||
t.Errorf("Test folder elements, got: %d, want: %d.", len(tmp0), 2)
|
||||
return
|
||||
}
|
||||
|
||||
tmp0, err = b.Ls("/tmp/test/")
|
||||
if err != nil {
|
||||
t.Errorf("Ls error %s", err)
|
||||
return
|
||||
}
|
||||
if len(tmp0) != 2 {
|
||||
t.Errorf("LS error: got: %d elmnt, want: %d", len(tmp0), 2)
|
||||
return
|
||||
}
|
||||
|
||||
// remove folder
|
||||
b.Rm("/tmp/test/")
|
||||
tmp0, err = b.Ls("/tmp/test/")
|
||||
if err == nil {
|
||||
t.Errorf("Removed folder still exists: %d", len(tmp0))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"testing"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var shareObj = Share{
|
||||
Backend: "foo",
|
||||
Id: "foo",
|
||||
Path: "/var/www/",
|
||||
Password: NewString("password"),
|
||||
Users: nil,
|
||||
CanRead: true,
|
||||
CanManageOwn: true,
|
||||
CanShare: true,
|
||||
Expire: func() *int64{
|
||||
a := int64(1537759505787)
|
||||
return &a
|
||||
}(),
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//// UPSERT
|
||||
|
||||
func TestShareSimpleUpsert(t *testing.T) {
|
||||
err := ShareUpsert(&shareObj);
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestShareMultipleUpsert(t *testing.T) {
|
||||
err := ShareUpsert(&shareObj);
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = ShareUpsert(&shareObj);
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = ShareGet(shareObj.Id)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestShareUpsertIsProperlyInserted(t *testing.T) {
|
||||
err := ShareUpsert(&shareObj);
|
||||
assert.NoError(t, err)
|
||||
|
||||
var obj Share
|
||||
obj.Id = "foo"
|
||||
obj, err = ShareGet(obj.Id)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, obj.Password)
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//// get
|
||||
|
||||
func TestShareGetNonExisting(t *testing.T) {
|
||||
var s Share = shareObj
|
||||
s.Id = "nothing"
|
||||
_, err := ShareGet(s.Id);
|
||||
assert.Error(t, err, "Shouldn't be able to get something that doesn't exist yet")
|
||||
}
|
||||
|
||||
func TestShareGetExisting(t *testing.T) {
|
||||
err := ShareUpsert(&shareObj);
|
||||
assert.NoError(t, err, "Upsert issue")
|
||||
|
||||
_, err = ShareGet(shareObj.Id);
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestShareGetExistingMakeSureDataIsOk(t *testing.T) {
|
||||
err := ShareUpsert(&shareObj);
|
||||
assert.NoError(t, err, "Upsert issue")
|
||||
|
||||
var obj Share
|
||||
obj.Id = "foo"
|
||||
obj.Backend = shareObj.Backend
|
||||
obj, err = ShareGet(obj.Id);
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "foo", obj.Id)
|
||||
assert.Equal(t, "/var/www/", obj.Path)
|
||||
assert.Equal(t, true, obj.CanManageOwn)
|
||||
assert.Equal(t, true, obj.CanShare)
|
||||
assert.Equal(t, true, obj.CanRead)
|
||||
assert.Equal(t, false, obj.CanWrite)
|
||||
assert.Equal(t, false, obj.CanUpload)
|
||||
assert.Equal(t, "foo", obj.Backend)
|
||||
assert.Equal(t, shareObj.Expire, obj.Expire)
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//// LIST
|
||||
|
||||
func TestShareListAll(t *testing.T) {
|
||||
// Initialise test
|
||||
err := ShareUpsert(&shareObj);
|
||||
assert.NoError(t, err, "Upsert issue")
|
||||
|
||||
// Actual test
|
||||
list, err := ShareList(shareObj.Backend, shareObj.Path)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, list, 1)
|
||||
assert.NotNil(t, list[0].Password)
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//// DELETE
|
||||
|
||||
func TestShareDeleteShares(t *testing.T) {
|
||||
// Initialise test
|
||||
err := ShareUpsert(&shareObj);
|
||||
assert.NoError(t, err, "Upsert issue")
|
||||
shareObj, err = ShareGet(shareObj.Id)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Actual Test
|
||||
err = ShareDelete(shareObj.Id);
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = ShareGet(shareObj.Id)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//// PROOF
|
||||
|
||||
func TestShareVerifyEquivalence(t *testing.T) {
|
||||
p1 := Proof {
|
||||
Key: "password",
|
||||
Value: "I'm something random",
|
||||
}
|
||||
p2 := Proof {
|
||||
Key: p1.Key,
|
||||
Id: "hash",
|
||||
}
|
||||
res := shareProofAreEquivalent(p1, p2)
|
||||
assert.Equal(t, false, res)
|
||||
|
||||
p2.Id = Hash(p1.Key + "::" + p1.Value)
|
||||
res = shareProofAreEquivalent(p1, p2)
|
||||
assert.Equal(t, true, res)
|
||||
|
||||
p2.Key = "email"
|
||||
res = shareProofAreEquivalent(p1, p2)
|
||||
assert.Equal(t, false, res)
|
||||
|
||||
p1.Key = "email"
|
||||
p1.Value = "test@gmail.com,polo@gmail.com,jean@gmail.com"
|
||||
p2.Key = "email"
|
||||
p2.Id = Hash(p1.Key + "::" + "polo@gmail.com")
|
||||
res = shareProofAreEquivalent(p1, p2)
|
||||
assert.Equal(t, true, res)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user