diff options
Diffstat (limited to 'vendor/golang.org/x/crypto/openpgp/packet/userid.go')
-rw-r--r-- | vendor/golang.org/x/crypto/openpgp/packet/userid.go | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userid.go b/vendor/golang.org/x/crypto/openpgp/packet/userid.go new file mode 100644 index 0000000..d6bea7d --- /dev/null +++ b/vendor/golang.org/x/crypto/openpgp/packet/userid.go | |||
@@ -0,0 +1,160 @@ | |||
1 | // Copyright 2011 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 | |||
5 | package packet | ||
6 | |||
7 | import ( | ||
8 | "io" | ||
9 | "io/ioutil" | ||
10 | "strings" | ||
11 | ) | ||
12 | |||
13 | // UserId contains text that is intended to represent the name and email | ||
14 | // address of the key holder. See RFC 4880, section 5.11. By convention, this | ||
15 | // takes the form "Full Name (Comment) <email@example.com>" | ||
16 | type UserId struct { | ||
17 | Id string // By convention, this takes the form "Full Name (Comment) <email@example.com>" which is split out in the fields below. | ||
18 | |||
19 | Name, Comment, Email string | ||
20 | } | ||
21 | |||
22 | func hasInvalidCharacters(s string) bool { | ||
23 | for _, c := range s { | ||
24 | switch c { | ||
25 | case '(', ')', '<', '>', 0: | ||
26 | return true | ||
27 | } | ||
28 | } | ||
29 | return false | ||
30 | } | ||
31 | |||
32 | // NewUserId returns a UserId or nil if any of the arguments contain invalid | ||
33 | // characters. The invalid characters are '\x00', '(', ')', '<' and '>' | ||
34 | func NewUserId(name, comment, email string) *UserId { | ||
35 | // RFC 4880 doesn't deal with the structure of userid strings; the | ||
36 | // name, comment and email form is just a convention. However, there's | ||
37 | // no convention about escaping the metacharacters and GPG just refuses | ||
38 | // to create user ids where, say, the name contains a '('. We mirror | ||
39 | // this behaviour. | ||
40 | |||
41 | if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) { | ||
42 | return nil | ||
43 | } | ||
44 | |||
45 | uid := new(UserId) | ||
46 | uid.Name, uid.Comment, uid.Email = name, comment, email | ||
47 | uid.Id = name | ||
48 | if len(comment) > 0 { | ||
49 | if len(uid.Id) > 0 { | ||
50 | uid.Id += " " | ||
51 | } | ||
52 | uid.Id += "(" | ||
53 | uid.Id += comment | ||
54 | uid.Id += ")" | ||
55 | } | ||
56 | if len(email) > 0 { | ||
57 | if len(uid.Id) > 0 { | ||
58 | uid.Id += " " | ||
59 | } | ||
60 | uid.Id += "<" | ||
61 | uid.Id += email | ||
62 | uid.Id += ">" | ||
63 | } | ||
64 | return uid | ||
65 | } | ||
66 | |||
67 | func (uid *UserId) parse(r io.Reader) (err error) { | ||
68 | // RFC 4880, section 5.11 | ||
69 | b, err := ioutil.ReadAll(r) | ||
70 | if err != nil { | ||
71 | return | ||
72 | } | ||
73 | uid.Id = string(b) | ||
74 | uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id) | ||
75 | return | ||
76 | } | ||
77 | |||
78 | // Serialize marshals uid to w in the form of an OpenPGP packet, including | ||
79 | // header. | ||
80 | func (uid *UserId) Serialize(w io.Writer) error { | ||
81 | err := serializeHeader(w, packetTypeUserId, len(uid.Id)) | ||
82 | if err != nil { | ||
83 | return err | ||
84 | } | ||
85 | _, err = w.Write([]byte(uid.Id)) | ||
86 | return err | ||
87 | } | ||
88 | |||
89 | // parseUserId extracts the name, comment and email from a user id string that | ||
90 | // is formatted as "Full Name (Comment) <email@example.com>". | ||
91 | func parseUserId(id string) (name, comment, email string) { | ||
92 | var n, c, e struct { | ||
93 | start, end int | ||
94 | } | ||
95 | var state int | ||
96 | |||
97 | for offset, rune := range id { | ||
98 | switch state { | ||
99 | case 0: | ||
100 | // Entering name | ||
101 | n.start = offset | ||
102 | state = 1 | ||
103 | fallthrough | ||
104 | case 1: | ||
105 | // In name | ||
106 | if rune == '(' { | ||
107 | state = 2 | ||
108 | n.end = offset | ||
109 | } else if rune == '<' { | ||
110 | state = 5 | ||
111 | n.end = offset | ||
112 | } | ||
113 | case 2: | ||
114 | // Entering comment | ||
115 | c.start = offset | ||
116 | state = 3 | ||
117 | fallthrough | ||
118 | case 3: | ||
119 | // In comment | ||
120 | if rune == ')' { | ||
121 | state = 4 | ||
122 | c.end = offset | ||
123 | } | ||
124 | case 4: | ||
125 | // Between comment and email | ||
126 | if rune == '<' { | ||
127 | state = 5 | ||
128 | } | ||
129 | case 5: | ||
130 | // Entering email | ||
131 | e.start = offset | ||
132 | state = 6 | ||
133 | fallthrough | ||
134 | case 6: | ||
135 | // In email | ||
136 | if rune == '>' { | ||
137 | state = 7 | ||
138 | e.end = offset | ||
139 | } | ||
140 | default: | ||
141 | // After email | ||
142 | } | ||
143 | } | ||
144 | switch state { | ||
145 | case 1: | ||
146 | // ended in the name | ||
147 | n.end = len(id) | ||
148 | case 3: | ||
149 | // ended in comment | ||
150 | c.end = len(id) | ||
151 | case 6: | ||
152 | // ended in email | ||
153 | e.end = len(id) | ||
154 | } | ||
155 | |||
156 | name = strings.TrimSpace(id[n.start:n.end]) | ||
157 | comment = strings.TrimSpace(id[c.start:c.end]) | ||
158 | email = strings.TrimSpace(id[e.start:e.end]) | ||
159 | return | ||
160 | } | ||