diff --git a/cache/file.go b/cache/file.go index 4b030980..691ce7cd 100644 --- a/cache/file.go +++ b/cache/file.go @@ -22,6 +22,7 @@ import ( "encoding/json" "fmt" "io" + "io/ioutil" "os" "path/filepath" "reflect" @@ -222,33 +223,13 @@ func exists(path string) (bool, error) { // FileGetContents Get bytes to file. // if non-exist, create this file. func FileGetContents(filename string) (data []byte, e error) { - f, e := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm) - if e != nil { - return - } - defer f.Close() - stat, e := f.Stat() - if e != nil { - return - } - data = make([]byte, stat.Size()) - result, e := f.Read(data) - if e != nil || int64(result) != stat.Size() { - return nil, e - } - return + return ioutil.ReadFile(filename) } // FilePutContents Put bytes to file. // if non-exist, create this file. func FilePutContents(filename string, content []byte) error { - fp, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm) - if err != nil { - return err - } - defer fp.Close() - _, err = fp.Write(content) - return err + return ioutil.WriteFile(filename, content, os.ModePerm) } // GobEncode Gob encodes file cache item. diff --git a/plugins/apiauth/apiauth.go b/plugins/apiauth/apiauth.go index 10636d1c..f816029c 100644 --- a/plugins/apiauth/apiauth.go +++ b/plugins/apiauth/apiauth.go @@ -56,6 +56,7 @@ package apiauth import ( + "bytes" "crypto/hmac" "crypto/sha256" "encoding/base64" @@ -128,53 +129,32 @@ func APISecretAuth(f AppIDToAppSecret, timeout int) beego.FilterFunc { // Signature used to generate signature with the appsecret/method/params/RequestURI func Signature(appsecret, method string, params url.Values, RequestURL string) (result string) { - var query string + var b bytes.Buffer + keys := make([]string, len(params)) pa := make(map[string]string) for k, v := range params { pa[k] = v[0] + keys = append(keys, k) } - vs := mapSorter(pa) - vs.Sort() - for i := 0; i < vs.Len(); i++ { - if vs.Keys[i] == "signature" { + + sort.Strings(keys) + + for _, key := range keys { + if key == "signature" { continue } - if vs.Keys[i] != "" && vs.Vals[i] != "" { - query = fmt.Sprintf("%v%v%v", query, vs.Keys[i], vs.Vals[i]) + + val := pa[key] + if key != "" && val != "" { + b.WriteString(key) + b.WriteString(val) } } - stringToSign := fmt.Sprintf("%v\n%v\n%v\n", method, query, RequestURL) + + stringToSign := fmt.Sprintf("%v\n%v\n%v\n", method, b.String(), RequestURL) sha256 := sha256.New hash := hmac.New(sha256, []byte(appsecret)) hash.Write([]byte(stringToSign)) return base64.StdEncoding.EncodeToString(hash.Sum(nil)) } - -type valSorter struct { - Keys []string - Vals []string -} - -func mapSorter(m map[string]string) *valSorter { - vs := &valSorter{ - Keys: make([]string, 0, len(m)), - Vals: make([]string, 0, len(m)), - } - for k, v := range m { - vs.Keys = append(vs.Keys, k) - vs.Vals = append(vs.Vals, v) - } - return vs -} - -func (vs *valSorter) Sort() { - sort.Sort(vs) -} - -func (vs *valSorter) Len() int { return len(vs.Keys) } -func (vs *valSorter) Less(i, j int) bool { return vs.Keys[i] < vs.Keys[j] } -func (vs *valSorter) Swap(i, j int) { - vs.Vals[i], vs.Vals[j] = vs.Vals[j], vs.Vals[i] - vs.Keys[i], vs.Keys[j] = vs.Keys[j], vs.Keys[i] -} diff --git a/plugins/apiauth/apiauth_test.go b/plugins/apiauth/apiauth_test.go new file mode 100644 index 00000000..1f56cb0f --- /dev/null +++ b/plugins/apiauth/apiauth_test.go @@ -0,0 +1,20 @@ +package apiauth + +import ( + "net/url" + "testing" +) + +func TestSignature(t *testing.T) { + appsecret := "beego secret" + method := "GET" + RequestURL := "http://localhost/test/url" + params := make(url.Values) + params.Add("arg1", "hello") + params.Add("arg2", "beego") + + signature := "mFdpvLh48ca4mDVEItE9++AKKQ/IVca7O/ZyyB8hR58=" + if Signature(appsecret, method, params, RequestURL) != signature { + t.Error("Signature error") + } +} diff --git a/session/sess_file.go b/session/sess_file.go index 132f5a00..50687c9e 100644 --- a/session/sess_file.go +++ b/session/sess_file.go @@ -15,8 +15,7 @@ package session import ( - "errors" - "io" + "fmt" "io/ioutil" "net/http" "os" @@ -135,6 +134,9 @@ func (fp *FileProvider) SessionRead(sid string) (Store, error) { } else { return nil, err } + + defer f.Close() + os.Chtimes(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), time.Now(), time.Now()) var kv map[interface{}]interface{} b, err := ioutil.ReadAll(f) @@ -149,7 +151,7 @@ func (fp *FileProvider) SessionRead(sid string) (Store, error) { return nil, err } } - f.Close() + ss := &FileSessionStore{sid: sid, values: kv} return ss, nil } @@ -204,49 +206,58 @@ func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (Store, error) { filepder.lock.Lock() defer filepder.lock.Unlock() - err := os.MkdirAll(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1])), 0777) - if err != nil { - SLogger.Println(err.Error()) - } - err = os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777) - if err != nil { - SLogger.Println(err.Error()) - } - _, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) - var newf *os.File + oldPath := path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1])) + oldSidFile := path.Join(oldPath, oldsid) + newPath := path.Join(fp.savePath, string(sid[0]), string(sid[1])) + newSidFile := path.Join(newPath, sid) + + // new sid file is exist + _, err := os.Stat(newSidFile) if err == nil { - return nil, errors.New("newsid exist") - } else if os.IsNotExist(err) { - newf, err = os.Create(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) + return nil, fmt.Errorf("newsid %s exist", newSidFile) } - _, err = os.Stat(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1]), oldsid)) - var f *os.File - if err == nil { - f, err = os.OpenFile(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1]), oldsid), os.O_RDWR, 0777) - io.Copy(newf, f) - } else if os.IsNotExist(err) { - newf, err = os.Create(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) - } else { - return nil, err - } - f.Close() - os.Remove(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1]))) - os.Chtimes(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), time.Now(), time.Now()) - var kv map[interface{}]interface{} - b, err := ioutil.ReadAll(newf) + err = os.MkdirAll(newPath, 0777) if err != nil { - return nil, err + SLogger.Println(err.Error()) } - if len(b) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = DecodeGob(b) + + // if old sid file exist + // 1.read and parse file content + // 2.write content to new sid file + // 3.remove old sid file, change new sid file atime and ctime + // 4.return FileSessionStore + _, err = os.Stat(oldSidFile) + if err == nil { + b, err := ioutil.ReadFile(oldSidFile) if err != nil { return nil, err } + + var kv map[interface{}]interface{} + if len(b) == 0 { + kv = make(map[interface{}]interface{}) + } else { + kv, err = DecodeGob(b) + if err != nil { + return nil, err + } + } + + ioutil.WriteFile(newSidFile, b, 0777) + os.Remove(oldSidFile) + os.Chtimes(newSidFile, time.Now(), time.Now()) + ss := &FileSessionStore{sid: sid, values: kv} + return ss, nil } - ss := &FileSessionStore{sid: sid, values: kv} + + // if old sid file not exist, just create new sid file and return + newf, err := os.Create(newSidFile) + if err != nil { + return nil, err + } + newf.Close() + ss := &FileSessionStore{sid: sid, values: make(map[interface{}]interface{})} return ss, nil }