e3db-go: github.com/tozny/e3db-go Index | Examples | Files | Directories

package e3db

import "github.com/tozny/e3db-go"

Package e3db provides programmatic access to the e3db API/Innovault service for the secure transmission and storage of arbitrary data encrypted locally using this SDK.

Official documentation for e3db can be found at https://tozny.com/documentation/e3db/

If not using go mod command for your project:

import "github.com/tozny/e3db-go"

Otherwise

import "github.com/tozny/e3db-go/v2"

Code:

package main

// This example interacts with the "feedback" mechanism in the CLI(https://github.com/tozny/e3db/releases). If you run
// this code, it will share text with Tozny in an end-to-end encrypted manner.

import (
    "context"
    "fmt"
    "github.com/tozny/e3db-go/v2"
    "log"
)

func chk(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

func printRecords(recordType string) {
    client, err := e3db.GetDefaultClient()
    chk(err)

    // Query for all records and print them out
    query := e3db.Q{} // queries all records
    if recordType != "" {
        query = e3db.Q{ContentTypes: []string{recordType}}
    }
    cursor := client.Query(context.Background(), query)
    for {
        record, err := cursor.Next()
        if err == e3db.Done {
            break
        } else if err != nil {
            chk(err)
        }
        fmt.Println("\t" + record.Meta.RecordID + " " + record.Meta.Type)
    }
}

func main() {

    // Accessing the default profile.
    // You must run e3db RegisterClient before this will work:
    client, err := e3db.GetDefaultClient()
    chk(err)

    fmt.Println("Current list of records:")
    printRecords("")

    // Create a new "feedback" record; this is the type the CLI uses
    feedbackData := make(map[string]string)
    feedbackData["comment"] = "This is some example feedback!"
    feedbackData["interface"] = "Go Example Code"
    record, err := client.Write(context.Background(), "feedback", feedbackData, nil)
    chk(err)

    // Read back the feedback we just put into the database
    newFeedbackRecord, err := client.Read(context.Background(), record.Meta.RecordID)
    chk(err)
    fmt.Println("Read record id " + record.Meta.RecordID + ": " + newFeedbackRecord.Data["comment"])

    // Fetch the Tozny feedback email address public key and client ID
    feedbackClient, err := client.GetClientInfo(context.Background(), "db1744b9-3fb6-4458-a291-0bc677dba08b")
    chk(err)

    // Share all "feedback" records with that user ID.
    err = client.Share(context.Background(), "feedback", feedbackClient.ClientID)
    chk(err)

    fmt.Println("Current list of records after adding:")
    printRecords("feedback")

    // Delete the record we just created to keep things tidy.
    // Comment out this line if you want to keep it
    err = client.Delete(context.Background(), record.Meta.RecordID, record.Meta.Version)
    chk(err)

    fmt.Println("Current list of records after deleting:")
    printRecords("feedback")
}

Index

Examples

Package Files

client.go config.go crypto.go query.go

Variables

var Done = errors.New("iteration complete")

Done is returned by Next when iteration is complete.

func GenerateKeyPair Uses

func GenerateKeyPair() (string, string, error)

GenerateKeyPair creates a new Curve25519 keypair for cryptographic operations.

func ProfileExists Uses

func ProfileExists(profile string) bool

ProfileExists returns true if a configuration exists for the given profile name.

func SaveConfig Uses

func SaveConfig(profile string, opts *ClientOpts) error

SaveConfig writes an E3DB client configuration to a profile.

func SaveDefaultConfig Uses

func SaveDefaultConfig(opts *ClientOpts) error

SaveDefaultConfig writes an E3DB client configuration to a profile.

type Channel Uses

type Channel struct {
    Application string `json:"application"`
    Type        string `json:"type"`
    Subject     string `json:"subject"`
}

Channel contains information defining the channel to which a client wishes to connect.

type Client Uses

type Client struct {
    Options ClientOpts
    // contains filtered or unexported fields
}

Client is an authenticated connection to the E3DB service, providing access to end-to-end encrypted data stored in the database.

func GetClient Uses

func GetClient(opts ClientOpts) (*Client, error)

GetClient creates an E3DB client given a custom set of options. Use 'GetConfig' to load options from a configuration profile.

func GetDefaultClient Uses

func GetDefaultClient() (*Client, error)

GetDefaultClient loads the default E3DB configuration profile and creates a client using those options.

func (*Client) Backup Uses

func (c *Client) Backup(ctx context.Context, clientID string, registrationToken string) error

Backup backs up the client's credentials to an account with which it's registered.

func (*Client) Delete Uses

func (c *Client) Delete(ctx context.Context, recordID string, version string) error

Delete removes a record, with optional optimistic locking.

func (*Client) GetClientInfo Uses

func (c *Client) GetClientInfo(ctx context.Context, clientID string) (*ClientInfo, error)

GetClientInfo queries the E3DB server for a client's public information given its client UUID.

func (*Client) GetIncomingSharing Uses

func (c *Client) GetIncomingSharing(ctx context.Context) ([]IncomingSharingPolicy, error)

GetIncomingSharing returns a list of writers and types of records that are currently shared with me.

func (*Client) GetOutgoingSharing Uses

func (c *Client) GetOutgoingSharing(ctx context.Context) ([]OutgoingSharingPolicy, error)

GetOutgoingSharing returns a list of readers and types of records that I am currently sharing.

func (*Client) NewEventSource Uses

func (c *Client) NewEventSource(ctx context.Context) (*EventSource, error)

NewEventSource is a factory that creates a new EventSource object for the given client, allowing for incoming events from the e3db server to be ingested by a client application.

func (*Client) Query Uses

func (c *Client) Query(ctx context.Context, q Q) *Cursor

Query executes a database query given a set of search parameters, returning a cursor that can be iterated over to loop through the result set.

func (*Client) Read Uses

func (c *Client) Read(ctx context.Context, recordID string) (*Record, error)

Read reads a record given a record ID, decrypts it, and returns the result.

func (*Client) ReadFields Uses

func (c *Client) ReadFields(ctx context.Context, recordID string, fields []string) (*Record, error)

ReadFields reads a record given a record ID, selecting a subset of fields, and returns a decrypted result.

func (*Client) Share Uses

func (c *Client) Share(ctx context.Context, recordType string, readerID string) error

Share grants another e3db client permission to read records of the specified record type.

func (*Client) Unshare Uses

func (c *Client) Unshare(ctx context.Context, recordType string, readerID string) error

Unshare revokes another e3db client's permission to read records of the given record type.

func (*Client) Update Uses

func (c *Client) Update(ctx context.Context, record *Record) error

Update a record, if the version field matches the version stored by E3DB.

Returns HTTP 409 (Conflict) in error if the record cannot be updated.

func (*Client) Write Uses

func (c *Client) Write(ctx context.Context, recordType string, data map[string]string, plain map[string]string) (*Record, error)

Write writes a new encrypted record to the database. Returns the new record (with the original, unencrypted data)

type ClientDetails Uses

type ClientDetails struct {
    ClientID  string    `json:"client_id"`
    ApiKeyID  string    `json:"api_key_id"`
    ApiSecret string    `json:"api_secret"`
    PublicKey ClientKey `json:"public_key"`
    Name      string    `json:"name"`
}

ClientDetails contains information about a newly-registered E3DB client

func RegisterClient Uses

func RegisterClient(registrationToken string, clientName string, publicKey string, privateKey string, backup bool, apiURL string) (*ClientDetails, error)

RegisterClient creates a new client for a given InnoVault account

Code:

package main

// This program provides a simple example illustrating how to programmatically
// register a client with InnoVault and e3db. In some situations, it's preferable
// to register a client from the server or system that will be using its
// credentials (to ensure that all data is truly encrypted from end-to-end
// with no possibilities of a credential leak). For more detailed information,
// please see the documentation home page: https://tozny.com/documentation/e3db
//
// Author::    Eric Mann (eric@tozny.com)
// Copyright:: Copyright (c) 2017 Tozny, LLC
// License::   Public Domain

import (
    "crypto/rand"
    "encoding/base64"
    "fmt"
    "log"
    "os"

    "github.com/tozny/e3db-go/v2"
)

// randomSecretKey is otherwise private to the client and is used to generate
// a random string ... it's not actually used for cryptographic operations
// in this example.
func randomSecretKey() *[32]byte {
    key := &[32]byte{}
    _, err := rand.Read(key[:])
    if err != nil {
        // we don't expect this to fail
        panic("random number generation failed")
    }

    return key
}

func main() {
    // A registration token is required to set up a client. In this situation,
    // we assume an environment variable called REGISTRATION_TOKEN is set
    token := os.Getenv("REGISTRATION_TOKEN")

    // Clients can either create new cryptographic keypairs, or load in a pre-defined
    // pair of Curve25519 keys. In this situation, we will generate a new keypair.
    public_key, private_key, err := e3db.GenerateKeyPair()

    fmt.Fprintf(os.Stdout, "Public Key:  %s\n", public_key)
    fmt.Fprintf(os.Stdout, "Private Key: %s\n", private_key)

    // Clients must be registered with a name unique to your account to help
    // differentiate between different sets of credentials in the Admin Console.
    // In this example, the name is set at random
    client_name := "client_" + base64.RawURLEncoding.EncodeToString(randomSecretKey()[:8])

    fmt.Fprintf(os.Stdout, "Client Name: %s\n", client_name)

    // Passing all of the data above into the registration routine will create
    // a new client with the system. Remember to keep your private key private!
    client_info, err := e3db.RegisterClient(token, client_name, public_key, "", false, "https://api.e3db.com")
    if err != nil {
        fmt.Fprintf(os.Stderr, "Unhandled error: %s\n", err)
        log.Fatal(err)
    }

    // Optionally, you can automatically back up the credentials of the newly-created
    // client to your InnoVault account (accessible via https://console.tozny.com) by
    // passing your private key and a backup flag when registering. The private key is
    // not sent anywhere, but is used by the newly-created client to sign an encrypted
    // copy of its credentials that is itself stored in e3db for later use.
    //
    // Client credentials are not backed up by default.

    // client_info := e3db.RegisterClient(token, client_name, public_key, private_key, true, "https://api.e3db.com")
    // if err != nil {
    //   fmt.Fprintf(os.Stderr, "Unhandled error: %s\n", err)
    //   log.Fatal(err)
    // }

    fmt.Fprintf(os.Stdout, "Client ID:   %s\n", client_info.ClientID)
    fmt.Fprintf(os.Stdout, "API Key ID:  %s\n", client_info.ApiKeyID)
    fmt.Fprintf(os.Stdout, "API Secret:  %s\n", client_info.ApiSecret)

    // ---------------------------------------------------------
    // Usage
    // ---------------------------------------------------------

    // Once the client is registered, you can use it immediately to create the
    // configuration used to instantiate a Client that can communicate with
    // e3db directly.

    pubBytes, _ := base64.RawURLEncoding.DecodeString(public_key)
    privBytes, _ := base64.RawURLEncoding.DecodeString(private_key)

    config := &e3db.ClientOpts{
        ClientID:    client_info.ClientID,
        ClientEmail: "",
        APIKeyID:    client_info.ApiKeyID,
        APISecret:   client_info.ApiSecret,
        PublicKey:   e3db.MakePublicKey(pubBytes),
        PrivateKey:  e3db.MakePrivateKey(privBytes),
        APIBaseURL:  "https://api.e3db.com",
        Logging:     false,
    }

    // Now create a client using that configuration.
    _, err = e3db.GetClient(*config)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Unhandled error: %s\n", err)
        log.Fatal(err)
    }

    // From this point on, the new client can be used as any other client to read
    // write, delete, and query for records. See the `simple.rb` documentation
    // for more complete examples ...
}

type ClientInfo Uses

type ClientInfo struct {
    ClientID  string    `json:"client_id"`
    PublicKey ClientKey `json:"public_key"`
    Validated bool      `json:"validated"`
}

ClientInfo contains information sent by the E3DB service about a client.

type ClientKey Uses

type ClientKey struct {
    Curve25519 string `json:"curve25519"`
}

ClientKey contains a cryptographic key for use in client operations.

type ClientOpts Uses

type ClientOpts struct {
    ClientID    string
    ClientEmail string
    APIKeyID    string
    APISecret   string
    PublicKey   PublicKey
    PrivateKey  PrivateKey
    APIBaseURL  string
    Logging     bool
}

ClientOpts contains options for configuring an E3DB client.

func DefaultConfig Uses

func DefaultConfig() (*ClientOpts, error)

DefaultConfig loads the default E3DB configuration.

func GetConfig Uses

func GetConfig(profile string) (*ClientOpts, error)

GetConfig loads an E3DB client configuration from a configuration file given the name of the profile.

type Cursor Uses

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

Cursor represents an iterator into a recordset returned by 'e3db.Query'.

func (*Cursor) Next Uses

func (c *Cursor) Next() (*Record, error)

Next returns the item at the current iterator position (if one is available).

type Event Uses

type Event struct {
    Time        time.Time         `json:"time"`
    Application string            `json:"application"`
    Type        string            `json:"type"`
    Action      string            `json:"action"`
    Subject     string            `json:"subject"`
    Producer    string            `json:"producer"`
    Context     map[string]string `json:"context"`
}

Event is an object representing the JSON blob dispatched from e3db in response to serverside events.

type EventSource Uses

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

EventSource represents an open socket to the e3db Event source.

func (*EventSource) Close Uses

func (c *EventSource) Close() error

Close the underlying websocket connection.

func (*EventSource) Events Uses

func (c *EventSource) Events() <-chan Event

Events produces a one-way version of the event-bearing channel.

func (*EventSource) Subscribe Uses

func (c *EventSource) Subscribe(channel Channel)

Subscribe to a specific event stream.

func (*EventSource) Unsubscribe Uses

func (c *EventSource) Unsubscribe(channel Channel)

Unsubscribe from a specific event stream.

type IncomingSharingPolicy Uses

type IncomingSharingPolicy struct {
    WriterID   string `json:"writer_id"`
    Type       string `json:"record_type"`
    WriterName string `json:"writer_name"`
}

IncomingSharingPolicy contains information about who has shared what type of records with me.

type Meta Uses

type Meta struct {
    RecordID     string            `json:"record_id,omitempty"`
    WriterID     string            `json:"writer_id"`
    UserID       string            `json:"user_id"`
    Type         string            `json:"type"`
    Plain        map[string]string `json:"plain"`
    Created      time.Time         `json:"created"`
    LastModified time.Time         `json:"last_modified"`
    Version      string            `json:"version,omitempty"`
}

Meta contains meta-information about an E3DB record, such as who wrote it, when it was written, and the type of the data stored.

type OutgoingSharingPolicy Uses

type OutgoingSharingPolicy struct {
    ReaderID   string `json:"reader_id"`
    Type       string `json:"record_type"`
    ReaderName string `json:"reader_name"`
}

OutgoingSharingPolicy contains information about who and what types of records I have shared with.

type PrivateKey Uses

type PrivateKey *[privateKeySize]byte

PrivateKey is an alias of a 32-byte array representing the private key component.

func MakePrivateKey Uses

func MakePrivateKey(b []byte) PrivateKey

MakePrivateKey converts a byte array to a PrivateKey type.

type PublicKey Uses

type PublicKey *[publicKeySize]byte

PublicKey is an alias of a 32-byte array representing the public key component.

func MakePublicKey Uses

func MakePublicKey(b []byte) PublicKey

MakePublicKey converts a byte array to a PublicKey type.

type Q Uses

type Q struct {
    Count       int  `json:"count"`                  //The maximum number of records to return.
    IncludeData bool `json:"include_data,omitempty"` //If true, include record data with results.

    WriterIDs         []string          `json:"writer_ids,omitempty"`    //If not empty, limit results to records written by the given set of IDs.
    UserIDs           []string          `json:"user_ids,omitempty"`      //If not null, limit results to records about given set of IDs.
    RecordIDs         []string          `json:"record_ids,omitempty"`    //If not empty, limit results to the records specified.
    ContentTypes      []string          `json:"content_types,omitempty"` //If not empty, limit results to records of the given types.
    AfterIndex        int               `json:"after_index,omitempty"`   //If greater than 0, limit results to the records appearing "after" the given index.
    Plain             map[string]string `json:"plain,omitempty"`
    IncludeAllWriters bool              `json:"include_all_writers,omitempty"` //If true, include all records shared with this client.
}

Q contains options for querying a set of records in the database.

type Record Uses

type Record struct {
    Meta Meta              `json:"meta"`
    Data map[string]string `json:"data"`
}

Record contains a plaintext 'Meta' object containing record metadata, along with decrypted fields in 'Data'. All data will be encrypted before it is stored in the E3DB service.

Directories

PathSynopsis
example
registration_example

Package e3db imports 22 packages (graph) and is imported by 2 packages. Updated 2018-11-28. Refresh now. Tools for package owners.