ssed

package
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 1, 2017 License: MIT Imports: 21 Imported by: 0

README

Guide to ssed

Coverage

bol is powered by a library to perform simple synchronization of encrypted documents (ssed), refereed to as the filesystem (fs). The following is the working document for the idea and implementation of the ssed fs.

Principles

In its essence, ssed is a file system composed of documents. A document is a list of entries. An entry is a map containing:

  • Entry name which must be unique (text)
  • Document which the entry belongs to (text)
  • Text content of the entry (text). Can also be indicator of "ignore document" / "ignore entry" to perform pseudo-deletion.
  • Timestamp of the creation time, used to sort for display (timestamp).
  • ModifiedTimestamp which is the last modified time, used to sort for ignoring (timestamp).

Each entry is stored in a separate file. The fs stores an entry by writing a JSON encoding the entry components to UUID.json where UUID is a sha256 hash of the entry content. The entry JSON is encrypted using 256-bit AES-GCM and stored as a hex string.

Compression and Encryption

All entries are encrypted when they are saved to disk as individual files. All of these files are then collapsed into a .tar.bz2 archive. Upon use, this archive is de-compressed, and then stored in a temp directory. Files are decrypted only when they are read.

Note: I'm aware that compression after encryption makes the archive slightly larger then encryption after compression. The increased costs are not exorbitant. Instead of compressing ~1,000 entries from 1MB to ~50k, instead it will compress to ~200k. The reason that I made this choice is the following: decompressing ~1,000 entries takes 2+ seconds on a typical laptop. If a password is not required for opening the archive, then the decompression can be performed asynchronously, while the password is being entered. Thus, program startup becomes an almost imperceptible <200 ms instead of a tiresome 2+ seconds. Decryption is much faster, and can be performed on the documents once the password is entered.

Synchronization

The local fs must always pull before it can push, because the local may be ahead or behind the remote. If the local fs is unable to pull, then it will avoid pushing during the session, in order not to overwrite newer entry on the remote.

Pulling is performed by unzipping the remote archive and local archive into the same directory and then rezipping them. Since all entries are stored as individual files, then if the local is ahead or behind, it will simply combine its file in.

Synchronization occurs in two steps. First the user initializes the filesystem. Then the password is supplied.

var fs ssed
fs.Init(username,method)
fmt.Printf("Enter password: ")
var password string
fmt.Scanln(&password) // user types in password
err = fs.Open(password) // does not run until Init(..) is finished
if err == nil {
  // good password
} else {
  // incorrect password
}

The Init(..) function will download the latest repo for username, and merge local+remote contents asynchronously. These steps are also decoupled from requiring any passwords, so they will not need to wait for a password to be entered. In the meantime, the password can be requested and supplied.

The method Open(..) checks the password by trying to decrypt an entry, and if it fails it returns an error. The function, Open(..) will not start until the initialization is done, but the initialization will run while the user spends time typing in a password.

Synchronization methods

There are two possible methods for syncing.

Method 1 - Server (~500 ms upload/download)

Syncing is provided using a server and client. The server has two routes which the client can use:

  • GET /repo - getting the latest archive, not protected, since it is encrypted
  • POST /repo - pushing changes to an archive, requires basic authorization
  • PUT /repo - add a user, requires basic authorization for credentials
Method 2 - SSH remote computer (~1500 ms upload/download) - not yet implemented

SSH is provided by the sftp library which can upload and download.

The user needs to provide:

  • server address
  • private SSH key OR password to access server

Adding and viewing entries

Adding/viewing entries can be done using the command line program or the server (though in a more limited way).

Other purposeful neglectfulness

After all, simple is part of ssed. In that light...

Diffs will not be stored. I'd like to optionally add an entry at any point in time without rebuilding history.

Files can not be deleted. It makes synchronization easier and also the disk cost of words is VERY small so its fine to store tons of text files (~1000's). If you plan on having 100,000+ entries, then this is not the tool for you.

Configuration

Whenever Init(name, method) is called, it generates a JSON containing the configuration file in `$HOME/.config/ssed/config.json:

[  
   {  
      "username":"zack",
      "method":"ssh://server"
   },
   {  
      "username":"bob",
      "method":"http://server2"
   },
   {  
      "username":"jill",
      "method":"http://server3"
   }
]

The first element of the configuration array is the default. Anytime a different configuration is used, it is popped from the list and added to the front and then resaved. The username is the name of the repo and the method is how to connect to the remote.

Implementation notes

Paths:

pathToLocalArchive:   $HOME/.cache/ssed/local/username.tar.bz2
pathToLocalEntries:   $HOME/.cache/ssed/local/username/
pathToRemoteArchive:  $HOME/.cache/ssed/remote/username.tar.bz2
pathToRemoteEntries:  $HOME/.cache/ssed/remote/username/
pathToTemp:           $HOME/.cache/ssed/temp
pathToConfigFile:     $HOME/.config/ssed/config.json

Only pathToTemp contains unencrypted things, so all files in that folder should be shredded upon exit.

Exporting

Exporting releases a JSON file that is simply a list of documents (which are lists of entries associated with each document).

[  
  {  
    "Name":"document1",
    "Entries":[  
      {  
        "text":"some text",
        "timestamp":"2014-11-20 13:00:00",
        "modified_timestamp":"2014-11-20 13:00:00",
        "document":"document1",
        "entry":"JwZGmuuykV"
      },
      {  
        "text":"some text4",
        "timestamp":"2013-11-20 13:00:00",
        "modified_timestamp":"2013-11-20 13:00:00",
        "document":"document1",
        "entry":"entry2"
      }
    ]
  }
]

Testing

This library can be tested by first running a bolserver and then using go test. E.g.

cd ../bolserver && go build && ./bolserver

Then in another terminal do:

go test -coverprofile cover.out && go tool cover -html=cover.out -o index.html && python3 -m http.server

Documentation

Index

Constants

This section is empty.

Variables

View Source
var LocalFolder string
View Source
var PathToTempFolder string

PathToTempFolder is the path to the temporary folder created by ssed

View Source
var RemoteFolder string

Functions

func CleanUp

func CleanUp()

CleanUp shreds all the temporary files

func DebugMode

func DebugMode()

DebugMode enables logging

func EraseAll

func EraseAll()

EraseAll erases the folders for configuration and cache for ssed

func EraseConfig

func EraseConfig()

EraseConfig erases the folder containing ssed configuration files

func HashPasswordSlow

func HashPasswordSlow(password string) (string, error)

HashPasswordSlow generates a bcrypt hash of the password using work factor 1048576.

Types

type Entry

type Entry struct {
	Text              string `json:"text"`
	Timestamp         string `json:"timestamp"`
	ModifiedTimestamp string `json:"modified_timestamp"`
	Document          string `json:"document"`
	Entry             string `json:"entry"`
	// contains filtered or unexported fields
}

Entry is the fundamental unit of an entry in any document

func GetBlankEntries

func GetBlankEntries() []Entry

GetBlankEntries returns an empty slice of entries

type Fs

type Fs struct {
	// contains filtered or unexported fields
}

Fs is the filesystem for ssed

func (*Fs) Close

func (ssed *Fs) Close() error

Close closes the repo and pushes if it was succesful pulling

func (*Fs) DeleteDocument

func (ssed *Fs) DeleteDocument(documentName string)

DeleteDocument will simply Update("ignore document",documentName,entryName,"")

func (*Fs) DeleteEntry

func (ssed *Fs) DeleteEntry(documentName, entryName string)

DeleteEntry will simply Update("ignore-entry",documentName,entryName,"")

func (*Fs) DumpAll

func (ssed *Fs) DumpAll() (string, error)

DumpAll dumps a file with current date and name, encyprted

func (*Fs) GetDocument

func (ssed *Fs) GetDocument(documentName string) []Entry

GetDocument returns a slice of all entries in that document

func (*Fs) GetDocumentOrEntry

func (ssed *Fs) GetDocumentOrEntry(ambiguous string) ([]Entry, bool, string, error)

GetDocumentOrEntry returns a entry slice that is either the entry or all entries in a document this is a useful function if you don't know whether an input is a document or an entry

func (*Fs) GetEntry

func (ssed *Fs) GetEntry(documentName, entryName string) (Entry, error)

GetEntry returns the entry with specified name and document

func (*Fs) GetPasswordFromPin

func (ssed *Fs) GetPasswordFromPin(pin string) (string, error)

GetPasswordFromPin allows to use a pin

func (*Fs) HasPinFile

func (ssed *Fs) HasPinFile() bool

HasPinFile

func (*Fs) Import

func (ssed *Fs) Import(filename string) error

Import imports an unencrypted bol file

func (*Fs) Init

func (ssed *Fs) Init(username, method string) error

Init initializes the repo If the username and the method are left blank it will automatically use first found in the config file

func (*Fs) ListDocuments

func (ssed *Fs) ListDocuments() []string

ListDocuments lists all documents available

func (*Fs) ListEntries

func (ssed *Fs) ListEntries() []string

ListEntries returns slice of all the entries in all documents

func (*Fs) Open

func (ssed *Fs) Open(password string) error

Open attempts to open a ssed repostiroy using the specified password

func (*Fs) ReturnMethod

func (ssed *Fs) ReturnMethod() string

ReturnMethod returns the current method being used

func (*Fs) ReturnUser

func (ssed *Fs) ReturnUser() string

ReturnUser returns the current user being used

func (*Fs) SetMethod

func (ssed *Fs) SetMethod(method string) error

SetMethod sets the server to obtain the synchronization

func (*Fs) SetPinFromPassword

func (ssed *Fs) SetPinFromPassword(pin string) error

SetPinFromPassword allows to use a pin

func (*Fs) Update

func (ssed *Fs) Update(text, documentName, entryName, timestamp string) error

Update make a new entry date can be empty, it will fill in the current date if so

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL