This is an automated email from the ASF dual-hosted git repository.

smihaylov pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-dta.git

commit dffff97e82de8d7dcf701a8687d622bc7856d55d
Author: Stanislav Mihaylov <[email protected]>
AuthorDate: Wed Sep 25 11:06:40 2019 +0300

    KeyStore interface to keep secrets
    
    File KeyStore implementation to keep secrets in a json file
---
 libs/keystore/filestore.go        | 111 ++++++++++++++++++++++++++++++++++++++
 libs/keystore/filestore_test.go   |  85 +++++++++++++++++++++++++++++
 libs/keystore/keystore.go         |  36 +++++++++++++
 libs/keystore/memorystore.go      |  59 ++++++++++++++++++++
 libs/keystore/memorystore_test.go |  46 ++++++++++++++++
 5 files changed, 337 insertions(+)

diff --git a/libs/keystore/filestore.go b/libs/keystore/filestore.go
new file mode 100644
index 0000000..5491563
--- /dev/null
+++ b/libs/keystore/filestore.go
@@ -0,0 +1,111 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package keystore
+
+import (
+       "encoding/json"
+       "io/ioutil"
+       "os"
+       "sync"
+
+       "github.com/pkg/errors"
+)
+
+// FileStore is the key Store implementation storing the keys in a file
+type FileStore struct {
+       sync.RWMutex
+       filePath string
+       keys     map[string][]byte
+}
+
+// NewFileStore creates a new FileStore
+func NewFileStore(filePath string) (Store, error) {
+       fs := &FileStore{
+               filePath: filePath,
+               keys:     map[string][]byte{},
+       }
+
+       if err := fs.loadKeys(); err != nil {
+               return nil, err
+       }
+
+       return fs, nil
+}
+
+// Set stores multiple keys at once
+func (f *FileStore) Set(name string, key []byte) error {
+       f.Lock()
+       defer f.Unlock()
+
+       f.keys[name] = make([]byte, len(key))
+       copy(f.keys[name], key)
+
+       return f.storeKeys()
+}
+
+// Get retrieves multiple keys
+func (f *FileStore) Get(name string) ([]byte, error) {
+       f.RLock()
+       defer f.RUnlock()
+
+       key, ok := f.keys[name]
+       if !ok {
+               return nil, ErrKeyNotFound
+       }
+
+       return key, nil
+}
+
+// TODO: Lock the file
+
+func (f *FileStore) loadKeys() error {
+       rawKeys, err := ioutil.ReadFile(f.filePath)
+       if err != nil {
+               if os.IsNotExist(err) {
+                       return nil
+               }
+               return errors.Wrap(err, "Load keys")
+       }
+
+       return json.Unmarshal(rawKeys, &(f).keys)
+}
+
+func (f *FileStore) storeKeys() error {
+       rawKeys, err := json.Marshal(f.keys)
+       if err != nil {
+               return err
+       }
+
+       // Get the file permissions
+       var perm os.FileMode
+       fi, err := os.Stat(f.filePath)
+       if err != nil {
+               if !os.IsNotExist(err) {
+                       return errors.Wrap(err, "Get key file permissions")
+               }
+               perm = 0600
+       } else {
+               perm = fi.Mode().Perm()
+       }
+
+       if err := ioutil.WriteFile(f.filePath, rawKeys, perm); err != nil {
+               return errors.Wrap(err, "Store keys")
+       }
+
+       return nil
+}
diff --git a/libs/keystore/filestore_test.go b/libs/keystore/filestore_test.go
new file mode 100644
index 0000000..7e946dd
--- /dev/null
+++ b/libs/keystore/filestore_test.go
@@ -0,0 +1,85 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package keystore
+
+import (
+       "bytes"
+       "crypto/rand"
+       "fmt"
+       "os"
+       "path/filepath"
+       "testing"
+       "time"
+)
+
+func TestFileStore(t *testing.T) {
+       keys := map[string][]byte{"key1": []byte{1}, "key2": []byte{1, 2}, 
"key3": []byte{1, 2, 3}}
+
+       fn := tmpFileName()
+       defer func() {
+               if err := os.Remove(fn); err != nil {
+                       t.Logf("Warning! Temp file could not be deleted (%v): 
%v", err, fn)
+               }
+       }()
+
+       fs, err := NewFileStore(fn)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // Set keys
+       for k, v := range keys {
+               fs.Set(k, v)
+       }
+
+       // Get Keys
+       for name, v := range keys {
+               key, err := fs.Get(name)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if !bytes.Equal(v, key) {
+                       t.Errorf("Key not match: %v. Expected: %v, Found: %v", 
name, v, key)
+               }
+
+       }
+
+       fs1, err := NewFileStore(fn)
+       if err != nil {
+               t.Fatal(err)
+       }
+       // Get Keys
+       for name, v := range keys {
+               key, err := fs1.Get(name)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if !bytes.Equal(v, key) {
+                       t.Errorf("Key not match: %v. Expected: %v, Found: %v", 
name, v, key)
+               }
+
+       }
+}
+
+func tmpFileName() string {
+       rnd := make([]byte, 8)
+       rand.Read(rnd)
+       ts := time.Now().UnixNano()
+
+       return filepath.Join(os.TempDir(), fmt.Sprintf("keystore-%v-%x.tmp", 
ts, rnd))
+}
diff --git a/libs/keystore/keystore.go b/libs/keystore/keystore.go
new file mode 100644
index 0000000..8b321c7
--- /dev/null
+++ b/libs/keystore/keystore.go
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package keystore - keep secrets
+*/
+package keystore
+
+import "github.com/pkg/errors"
+
+var (
+       // ErrKeyNotFound is returned when a key is not found in the store
+       ErrKeyNotFound = errors.New("Key not found")
+)
+
+// Store is the keystore interface
+type Store interface {
+       // Set stores multiple keys at once
+       Set(name string, key []byte) error
+       // Get retrieves multiple keys
+       Get(name string) ([]byte, error)
+}
diff --git a/libs/keystore/memorystore.go b/libs/keystore/memorystore.go
new file mode 100644
index 0000000..484a45f
--- /dev/null
+++ b/libs/keystore/memorystore.go
@@ -0,0 +1,59 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package keystore
+
+import (
+       "sync"
+)
+
+// MemoryStore is the in-memory implementation of key store
+type MemoryStore struct {
+       sync.RWMutex
+       keys map[string][]byte
+}
+
+// NewMemoryStore creates a new MemoryStore
+func NewMemoryStore() (Store, error) {
+       return &MemoryStore{
+               keys: map[string][]byte{},
+       }, nil
+}
+
+// Set stores multiple keys at once
+func (f *MemoryStore) Set(name string, key []byte) error {
+       f.Lock()
+       defer f.Unlock()
+
+       f.keys[name] = make([]byte, len(key))
+       copy(f.keys[name], key)
+
+       return nil
+}
+
+// Get retrieves multiple keys
+func (f *MemoryStore) Get(name string) ([]byte, error) {
+       f.RLock()
+       defer f.RUnlock()
+
+       key, ok := f.keys[name]
+       if !ok {
+               return nil, ErrKeyNotFound
+       }
+
+       return key, nil
+}
diff --git a/libs/keystore/memorystore_test.go 
b/libs/keystore/memorystore_test.go
new file mode 100644
index 0000000..5dd92a2
--- /dev/null
+++ b/libs/keystore/memorystore_test.go
@@ -0,0 +1,46 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package keystore
+
+import (
+       "bytes"
+       "testing"
+)
+
+func TestMemoryStore(t *testing.T) {
+       keys := map[string][]byte{"key1": []byte{1}, "key2": []byte{1, 2}, 
"key3": []byte{1, 2, 3}}
+
+       ms, err := NewMemoryStore()
+       if err != nil {
+               t.Fatal(err)
+       }
+       for k, v := range keys {
+               ms.Set(k, v)
+       }
+
+       for name, v := range keys {
+               key, err := ms.Get(name)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if !bytes.Equal(v, key) {
+                       t.Errorf("Key not match: %v. Expected: %v, Found: %v", 
name, v, key)
+               }
+
+       }
+}

Reply via email to