Пример #1
0
func read_message(r io.Reader) (NNTPMessage, error) {

	msg, err := mail.ReadMessage(r)
	var nntp nntpArticle

	if err == nil {
		nntp.headers = ArticleHeaders(msg.Header)
		content_type := nntp.ContentType()
		media_type, params, err := mime.ParseMediaType(content_type)
		if err != nil {
			log.Println("failed to parse media type", err, "for mime", content_type)
			return nil, err
		}
		boundary, ok := params["boundary"]
		if ok {
			partReader := multipart.NewReader(msg.Body, boundary)
			for {
				part, err := partReader.NextPart()
				if err == io.EOF {
					return nntp, nil
				} else if err == nil {
					hdr := part.Header
					// get content type of part
					part_type := hdr.Get("Content-Type")
					// parse content type
					media_type, _, err = mime.ParseMediaType(part_type)
					if err == nil {
						if media_type == "text/plain" {
							att := readAttachmentFromMimePart(part)
							if att != nil {
								nntp.message = att.(nntpAttachment)
								nntp.message.header.Set("Content-Type", part_type)
							}
						} else {
							// non plaintext gets added to attachments
							att := readAttachmentFromMimePart(part)
							if att != nil {
								nntp = nntp.Attach(att).(nntpArticle)
							}
						}
					} else {
						log.Println("part has no content type", err)
					}
					part.Close()
				} else {
					log.Println("failed to load part! ", err)
					return nil, err
				}
			}

		} else if media_type == "message/rfc822" {
			// tripcoded message
			sig := nntp.headers.Get("X-Signature-Ed25519-Sha512", "")
			pk := nntp.Pubkey()
			if pk == "" || sig == "" {
				log.Println("invalid sig or pubkey", sig, pk)
				return nil, errors.New("invalid headers")
			}
			log.Printf("got signed message from %s", pk)
			pk_bytes := unhex(pk)
			sig_bytes := unhex(sig)
			r := bufio.NewReader(msg.Body)
			crlf := []byte{13, 10}
			for {
				line, err := r.ReadBytes('\n')
				if err == io.EOF {
					break
				}
				nntp.signedPart.body.Write(line[:len(line)-1])
				nntp.signedPart.body.Write(crlf)
			}
			if nntp.signedPart.body.Len() < 2 {
				log.Println("signed body is too small")
			} else {
				body := nntp.signedPart.body.Bytes()[:nntp.signedPart.body.Len()-2]
				body_hash := sha512.Sum512(body)
				log.Printf("hash=%s", hexify(body_hash[:]))
				if nacl.CryptoVerifyFucky(body_hash[:], sig_bytes, pk_bytes) {
					log.Println("signature is valid :^)")
					return nntp, nil
				} else {
					log.Println("!!!signature is invalid!!!")
				}
			}
		} else {
			// plaintext attachment
			var buff bytes.Buffer
			_, err = io.Copy(&buff, msg.Body)
			nntp.message = createPlaintextAttachment(buff.String())
			return nntp, err
		}
	} else {
		log.Println("failed to read message", err)
		return nil, err
	}
	return nntp, err
}