mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	* Implement GPG API * Better handle error * Apply review recommendation + simplify database operations * Remove useless comments
		
			
				
	
	
		
			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
 | 
						|
}
 |