mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 11:28:24 +00:00 
			
		
		
		
	* Switch to keybase go-crypto (for some elliptic curve key) + test
* Use assert.NoError 
and add a little more context to failing test description
* Use assert.(No)Error everywhere 🌈
and assert.Error in place of .Nil/.NotNil
		
	
		
			
				
	
	
		
			161 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2011 The Go Authors. All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| package packet
 | |
| 
 | |
| import (
 | |
| 	"io"
 | |
| 	"io/ioutil"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // UserId contains text that is intended to represent the name and email
 | |
| // address of the key holder. See RFC 4880, section 5.11. By convention, this
 | |
| // takes the form "Full Name (Comment) <email@example.com>"
 | |
| type UserId struct {
 | |
| 	Id string // By convention, this takes the form "Full Name (Comment) <email@example.com>" which is split out in the fields below.
 | |
| 
 | |
| 	Name, Comment, Email string
 | |
| }
 | |
| 
 | |
| func hasInvalidCharacters(s string) bool {
 | |
| 	for _, c := range s {
 | |
| 		switch c {
 | |
| 		case '(', ')', '<', '>', 0:
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // NewUserId returns a UserId or nil if any of the arguments contain invalid
 | |
| // characters. The invalid characters are '\x00', '(', ')', '<' and '>'
 | |
| func NewUserId(name, comment, email string) *UserId {
 | |
| 	// RFC 4880 doesn't deal with the structure of userid strings; the
 | |
| 	// name, comment and email form is just a convention. However, there's
 | |
| 	// no convention about escaping the metacharacters and GPG just refuses
 | |
| 	// to create user ids where, say, the name contains a '('. We mirror
 | |
| 	// this behaviour.
 | |
| 
 | |
| 	if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	uid := new(UserId)
 | |
| 	uid.Name, uid.Comment, uid.Email = name, comment, email
 | |
| 	uid.Id = name
 | |
| 	if len(comment) > 0 {
 | |
| 		if len(uid.Id) > 0 {
 | |
| 			uid.Id += " "
 | |
| 		}
 | |
| 		uid.Id += "("
 | |
| 		uid.Id += comment
 | |
| 		uid.Id += ")"
 | |
| 	}
 | |
| 	if len(email) > 0 {
 | |
| 		if len(uid.Id) > 0 {
 | |
| 			uid.Id += " "
 | |
| 		}
 | |
| 		uid.Id += "<"
 | |
| 		uid.Id += email
 | |
| 		uid.Id += ">"
 | |
| 	}
 | |
| 	return uid
 | |
| }
 | |
| 
 | |
| func (uid *UserId) parse(r io.Reader) (err error) {
 | |
| 	// RFC 4880, section 5.11
 | |
| 	b, err := ioutil.ReadAll(r)
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 	uid.Id = string(b)
 | |
| 	uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // Serialize marshals uid to w in the form of an OpenPGP packet, including
 | |
| // header.
 | |
| func (uid *UserId) Serialize(w io.Writer) error {
 | |
| 	err := serializeHeader(w, packetTypeUserId, len(uid.Id))
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	_, err = w.Write([]byte(uid.Id))
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // parseUserId extracts the name, comment and email from a user id string that
 | |
| // is formatted as "Full Name (Comment) <email@example.com>".
 | |
| func parseUserId(id string) (name, comment, email string) {
 | |
| 	var n, c, e struct {
 | |
| 		start, end int
 | |
| 	}
 | |
| 	var state int
 | |
| 
 | |
| 	for offset, rune := range id {
 | |
| 		switch state {
 | |
| 		case 0:
 | |
| 			// Entering name
 | |
| 			n.start = offset
 | |
| 			state = 1
 | |
| 			fallthrough
 | |
| 		case 1:
 | |
| 			// In name
 | |
| 			if rune == '(' {
 | |
| 				state = 2
 | |
| 				n.end = offset
 | |
| 			} else if rune == '<' {
 | |
| 				state = 5
 | |
| 				n.end = offset
 | |
| 			}
 | |
| 		case 2:
 | |
| 			// Entering comment
 | |
| 			c.start = offset
 | |
| 			state = 3
 | |
| 			fallthrough
 | |
| 		case 3:
 | |
| 			// In comment
 | |
| 			if rune == ')' {
 | |
| 				state = 4
 | |
| 				c.end = offset
 | |
| 			}
 | |
| 		case 4:
 | |
| 			// Between comment and email
 | |
| 			if rune == '<' {
 | |
| 				state = 5
 | |
| 			}
 | |
| 		case 5:
 | |
| 			// Entering email
 | |
| 			e.start = offset
 | |
| 			state = 6
 | |
| 			fallthrough
 | |
| 		case 6:
 | |
| 			// In email
 | |
| 			if rune == '>' {
 | |
| 				state = 7
 | |
| 				e.end = offset
 | |
| 			}
 | |
| 		default:
 | |
| 			// After email
 | |
| 		}
 | |
| 	}
 | |
| 	switch state {
 | |
| 	case 1:
 | |
| 		// ended in the name
 | |
| 		n.end = len(id)
 | |
| 	case 3:
 | |
| 		// ended in comment
 | |
| 		c.end = len(id)
 | |
| 	case 6:
 | |
| 		// ended in email
 | |
| 		e.end = len(id)
 | |
| 	}
 | |
| 
 | |
| 	name = strings.TrimSpace(id[n.start:n.end])
 | |
| 	comment = strings.TrimSpace(id[c.start:c.end])
 | |
| 	email = strings.TrimSpace(id[e.start:e.end])
 | |
| 	return
 | |
| }
 |