1// Copyright 2013 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package packet 6 7import ( 8 "bytes" 9 "image" 10 "image/jpeg" 11 "io" 12 "io/ioutil" 13) 14 15const UserAttrImageSubpacket = 1 16 17// UserAttribute is capable of storing other types of data about a user 18// beyond name, email and a text comment. In practice, user attributes are typically used 19// to store a signed thumbnail photo JPEG image of the user. 20// See RFC 4880, section 5.12. 21type UserAttribute struct { 22 Contents []*OpaqueSubpacket 23} 24 25// NewUserAttributePhoto creates a user attribute packet 26// containing the given images. 27func NewUserAttributePhoto(photos ...image.Image) (uat *UserAttribute, err error) { 28 uat = new(UserAttribute) 29 for _, photo := range photos { 30 var buf bytes.Buffer 31 // RFC 4880, Section 5.12.1. 32 data := []byte{ 33 0x10, 0x00, // Little-endian image header length (16 bytes) 34 0x01, // Image header version 1 35 0x01, // JPEG 36 0, 0, 0, 0, // 12 reserved octets, must be all zero. 37 0, 0, 0, 0, 38 0, 0, 0, 0} 39 if _, err = buf.Write(data); err != nil { 40 return 41 } 42 if err = jpeg.Encode(&buf, photo, nil); err != nil { 43 return 44 } 45 uat.Contents = append(uat.Contents, &OpaqueSubpacket{ 46 SubType: UserAttrImageSubpacket, 47 Contents: buf.Bytes()}) 48 } 49 return 50} 51 52// NewUserAttribute creates a new user attribute packet containing the given subpackets. 53func NewUserAttribute(contents ...*OpaqueSubpacket) *UserAttribute { 54 return &UserAttribute{Contents: contents} 55} 56 57func (uat *UserAttribute) parse(r io.Reader) (err error) { 58 // RFC 4880, section 5.13 59 b, err := ioutil.ReadAll(r) 60 if err != nil { 61 return 62 } 63 uat.Contents, err = OpaqueSubpackets(b) 64 return 65} 66 67// Serialize marshals the user attribute to w in the form of an OpenPGP packet, including 68// header. 69func (uat *UserAttribute) Serialize(w io.Writer) (err error) { 70 var buf bytes.Buffer 71 for _, sp := range uat.Contents { 72 sp.Serialize(&buf) 73 } 74 if err = serializeHeader(w, packetTypeUserAttribute, buf.Len()); err != nil { 75 return err 76 } 77 _, err = w.Write(buf.Bytes()) 78 return 79} 80 81// ImageData returns zero or more byte slices, each containing 82// JPEG File Interchange Format (JFIF), for each photo in the 83// user attribute packet. 84func (uat *UserAttribute) ImageData() (imageData [][]byte) { 85 for _, sp := range uat.Contents { 86 if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 { 87 imageData = append(imageData, sp.Contents[16:]) 88 } 89 } 90 return 91} 92