Documentation ¶
Index ¶
- Constants
- Variables
- func SetGhostifyer(gh Ghostifyer) error
- type GhostString
- func (gs *GhostString) Equal(other *GhostString) bool
- func (gs *GhostString) GoString() string
- func (gs *GhostString) IsValid() bool
- func (gs *GhostString) MarshalBinary() ([]byte, error)
- func (gs *GhostString) MarshalJSON() ([]byte, error)
- func (gs *GhostString) MarshalText() ([]byte, error)
- func (gs *GhostString) String() string
- func (gs *GhostString) UnmarshalBinary(b []byte) error
- func (gs *GhostString) UnmarshalJSON(b []byte) error
- func (gs *GhostString) UnmarshalText(b []byte) error
- type Ghostifyer
- type KeyStore
- type TimestampedKey
Examples ¶
Constants ¶
const ( NamespaceMatchRegexp = "^[a-zA-Z][-\\._a-zA-Z0-9]{1,254}[a-zA-Z0-9]$" NamespaceSeparator = "::" Prefix = "👻:" Nonce = 12 )
const (
EnvKeyStoreKeyPrefix = "GHOSTSTRING_KEY_{{.Namespace}}_"
)
Variables ¶
var (
Err = errors.New("ghoststring error")
)
Functions ¶
func SetGhostifyer ¶
func SetGhostifyer(gh Ghostifyer) error
Types ¶
type GhostString ¶
GhostString wraps a string with a JSON marshaller that uses a namespace-scoped encrypting Ghostifyer registered via SetGhostifyer
Example ¶
package main import ( "encoding/json" "fmt" "regexp" "strings" "time" "github.com/rstudio/ghoststring" ) func main() { gh, err := ghoststring.NewAES256GCMSingleKeyGhostifyer( "example", "correct horse battery staple", ) if err != nil { panic(err) } if err := ghoststring.SetGhostifyer(gh); err != nil { panic(err) } type DiaryEntry struct { Timestamp time.Time `json:"timestamp"` Text ghoststring.GhostString `json:"text"` } type Diary struct { Author string `json:"author"` Entries []DiaryEntry `json:"entries"` } enc, err := json.MarshalIndent( &Diary{ Author: "Eagerly Anticipated", Entries: []DiaryEntry{ { Timestamp: time.UnixMicro(4), Text: ghoststring.GhostString{ Namespace: "example", Str: "Nights without you are so dark. I pray that someday you will return my flashlight.", }, }, { Timestamp: time.UnixMicro(-8001), Text: ghoststring.GhostString{ Namespace: "unknown", Str: "We may never know.", }, }, }, }, "", " ", ) if err != nil { panic(err) } encString := string(enc) if strings.Contains(encString, "We may never know.") || strings.Contains(encString, "Nights without you") { panic("not ghostly enough: contains cleartext") } if !strings.Contains(encString, `"text": ""`) { panic("not ghostly enough: lacking empty ghoststring") } if matched, err := regexp.MatchString(`.+"text": "👻:[^"]+"`, encString); !matched || err != nil { panic("not ghostly enough: lacking non-empty ghoststring") } fmt.Println("no peeking") }
Output: no peeking
func (*GhostString) Equal ¶
func (gs *GhostString) Equal(other *GhostString) bool
Equal compares this GhostString to another
func (*GhostString) GoString ¶ added in v0.3.0
func (gs *GhostString) GoString() string
func (*GhostString) IsValid ¶
func (gs *GhostString) IsValid() bool
IsValid checks that the wrapped string value is non-empty and the namespace is valid
func (*GhostString) MarshalBinary ¶ added in v0.3.0
func (gs *GhostString) MarshalBinary() ([]byte, error)
MarshalBinary allows GhostString to fulfill the encoding.BinaryMarshaler interface
func (*GhostString) MarshalJSON ¶
func (gs *GhostString) MarshalJSON() ([]byte, error)
MarshalJSON allows GhostString to fulfill the json.Marshaler interface. The lack of a namespace is considered an error.
func (*GhostString) MarshalText ¶ added in v0.3.0
func (gs *GhostString) MarshalText() ([]byte, error)
MarshalText allows GhostString to fulfill the encoding.TextMarshaler interface
func (*GhostString) String ¶
func (gs *GhostString) String() string
func (*GhostString) UnmarshalBinary ¶ added in v0.3.0
func (gs *GhostString) UnmarshalBinary(b []byte) error
UnmarshalBinary allows GhostString to fulfill the encoding.BinaryUnmarshaler interface
func (*GhostString) UnmarshalJSON ¶
func (gs *GhostString) UnmarshalJSON(b []byte) error
UnmarshalJSON allows GhostString to fulfill the json.Unmarshaler interface. The bytes are first unmarshaled as a string and then if non-empty are passed through an "unghostify" step. The expected structure of a marshalled GhostString is:
"{Prefix}base64({nonce}{namespace}{NamespaceSeparator}{opaque-value})"
where {nonce} has the length specified as Nonce.
func (*GhostString) UnmarshalText ¶ added in v0.3.0
func (gs *GhostString) UnmarshalText(b []byte) error
UnmarshalText allows GhostString to fulfill the encoding.TextUnmarshaler interface
type Ghostifyer ¶
type Ghostifyer interface { Namespace() string Ghostify(*GhostString) (string, error) Unghostify(string) (*GhostString, error) }
Ghostifyer encodes a GhostString into a string representation.
func NewAES256GCMMultiKeyGhostifyer ¶ added in v0.5.0
func NewAES256GCMMultiKeyGhostifyer(namespace string, keys KeyStore) Ghostifyer
NewAES256GCMMultiKeyGhostifyer creates a Ghostifyer with multiple timestamped keys that uses AES-256-GCM encryption with nonce assigned at the individual string level. The keystore.Latest will be used for encryption and any key in keystore.All may be used for decryption.
func NewAES256GCMSingleKeyGhostifyer ¶ added in v0.3.0
func NewAES256GCMSingleKeyGhostifyer(namespace, key string) (Ghostifyer, error)
NewAES256GCMSingleKeyGhostifyer creates a Ghostifyer with a single key that uses AES-256-GCM encryption with nonce assigned at the individual string level.
type KeyStore ¶ added in v0.5.0
type KeyStore interface { Latest(ctx context.Context) ([]byte, error) All(ctx context.Context) ([][]byte, error) }
func NewKeyStore ¶ added in v0.5.0
func NewKeyStore(namespace string, keys []*TimestampedKey) (KeyStore, error)