~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/golang.org/x/crypto/openpgp/packet/userid.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}