...

Source file src/github.com/go-kivik/kivik/v4/x/fsdb/cdb/security.go

Documentation: github.com/go-kivik/kivik/v4/x/fsdb/cdb

     1  // Licensed under the Apache License, Version 2.0 (the "License"); you may not
     2  // use this file except in compliance with the License. You may obtain a copy of
     3  // the License at
     4  //
     5  //  http://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     9  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    10  // License for the specific language governing permissions and limitations under
    11  // the License.
    12  
    13  package cdb
    14  
    15  import (
    16  	"context"
    17  	"encoding/json"
    18  	"os"
    19  	"path/filepath"
    20  
    21  	"gopkg.in/yaml.v3"
    22  
    23  	"github.com/go-kivik/kivik/v4/driver"
    24  	"github.com/go-kivik/kivik/v4/x/fsdb/cdb/decode"
    25  )
    26  
    27  // ReadSecurity reads the _security.{ext} document from path. If not found,
    28  // an empty security document is returned.
    29  func (fs *FS) ReadSecurity(ctx context.Context, path string) (*driver.Security, error) {
    30  	sec := new(driver.Security)
    31  	ext, err := fs.findSecurityExt(ctx, path)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  	if ext == "" {
    36  		return sec, nil
    37  	}
    38  	f, err := fs.fs.Open(filepath.Join(path, "_security."+ext))
    39  	if err == nil {
    40  		defer f.Close()
    41  		err := decode.Decode(f, ext, sec)
    42  		return sec, err
    43  	}
    44  	if !os.IsNotExist(err) {
    45  		return nil, err
    46  	}
    47  
    48  	return sec, nil
    49  }
    50  
    51  // findSecurityExt looks in path for the `_security` document by extension, and
    52  // returns the first matching extension it finds, or an empty string if the
    53  // security document is not found.
    54  func (fs *FS) findSecurityExt(ctx context.Context, path string) (string, error) {
    55  	for _, ext := range decode.Extensions() {
    56  		if err := ctx.Err(); err != nil {
    57  			return "", err
    58  		}
    59  		stat, err := fs.fs.Stat(filepath.Join(path, "_security."+ext))
    60  		if os.IsNotExist(err) {
    61  			continue
    62  		}
    63  		if err != nil {
    64  			return "", err
    65  		}
    66  		if stat.Mode().IsRegular() {
    67  			return ext, nil
    68  		}
    69  	}
    70  	return "", nil
    71  }
    72  
    73  // WriteSecurity overwrites the existing _security document, if it exists. If it
    74  // does not exist, it is created with the .json extension.
    75  func (fs *FS) WriteSecurity(ctx context.Context, path string, sec *driver.Security) error {
    76  	ext, err := fs.findSecurityExt(ctx, path)
    77  	if err != nil {
    78  		return err
    79  	}
    80  	if ext == "" {
    81  		ext = "json"
    82  	}
    83  	filename := filepath.Join(path, "_security."+ext)
    84  	tmp, err := fs.fs.TempFile(path, "_security."+ext)
    85  	if err != nil {
    86  		return err
    87  	}
    88  	var enc interface {
    89  		Encode(interface{}) error
    90  	}
    91  	switch ext {
    92  	case "json":
    93  		enc = json.NewEncoder(tmp)
    94  	case "yaml", "yml":
    95  		enc = yaml.NewEncoder(tmp)
    96  	}
    97  	if err := enc.Encode(sec); err != nil {
    98  		return err
    99  	}
   100  	if err := tmp.Close(); err != nil {
   101  		return err
   102  	}
   103  	return fs.fs.Rename(tmp.Name(), filename)
   104  }
   105  

View as plain text