// Package file implements signify file format package file import ( "bytes" "encoding/base64" "errors" "fmt" "io" "io/ioutil" "os" "strings" ) const ( EncMode os.FileMode = 0600 PubMode os.FileMode = 0644 SigMode os.FileMode = 0644 untrusted = "untrusted comment:" ) var ErrComment = errors.New("expected untrusted comment") // Block represents a encoded signify key or signature // // The encoded form is: // untrusted comment: comment // base64-encoded key // optional message type Block struct { Comment string Bytes []byte Message []byte // TODO replace with io.ReadCloser } func Encode(w io.Writer, b *Block) error { fmt.Fprintln(w, untrusted, b.Comment) fmt.Fprintln(w, base64.StdEncoding.EncodeToString(b.Bytes)) w.Write(b.Message) return nil } func EncodeToMemory(b *Block) []byte { buf := new(bytes.Buffer) Encode(buf, b) return buf.Bytes() } func EncodeFile(fname string, perm os.FileMode, b *Block) error { fd, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm) if err != nil { return err } defer fd.Close() return Encode(fd, b) } func Decode(data []byte) (*Block, error) { r := bytes.NewBuffer(data) comment, err := r.ReadString('\n') if err != nil { return nil, err } if !strings.HasPrefix(comment, untrusted) { return nil, ErrComment } raw, err := r.ReadString('\n') if err != nil { return nil, err } b, err := base64.StdEncoding.DecodeString(raw) if err != nil { return nil, err } message, err := ioutil.ReadAll(r) if err != nil { return nil, err } return &Block{ Comment: strings.TrimSpace(comment[len(untrusted):]), Bytes: b, Message: message, }, nil } func DecodeFile(fname string) (*Block, error) { body, err := ioutil.ReadFile(fname) if err != nil { return nil, err } return Decode(body) }