Merge pull request #621 from tamcore/feature/email-with-access-control
Make email publishing work, when access-control is enabled
This commit is contained in:
		
						commit
						33e75375fd
					
				
					 3 changed files with 40 additions and 0 deletions
				
			
		|  | @ -2582,6 +2582,11 @@ format is: | |||
| ntfy-$topic@ntfy.sh | ||||
| ``` | ||||
| 
 | ||||
| If [access control](config.md#access-control) is enabled, and the target topic does not support anonymous writes, e-mail publishing won't work without providing an authorized access token. That will change the format of the e-mail's recipient address to | ||||
| ``` | ||||
| ntfy-$topic+$token@ntfy.sh | ||||
| ``` | ||||
| 
 | ||||
| As of today, e-mail publishing only supports adding a [message title](#message-title) (the e-mail subject). Tags, priority, | ||||
| delay and other features are not supported (yet). Here's an example that will publish a message with the  | ||||
| title `You've Got Mail` to topic `sometopic` (see [ntfy.sh/sometopic](https://ntfy.sh/sometopic)): | ||||
|  |  | |||
|  | @ -65,6 +65,7 @@ type smtpSession struct { | |||
| 	backend *smtpBackend | ||||
| 	conn    *smtp.Conn | ||||
| 	topic   string | ||||
| 	token   string | ||||
| 	mu      sync.Mutex | ||||
| } | ||||
| 
 | ||||
|  | @ -81,6 +82,7 @@ func (s *smtpSession) Mail(from string, opts *smtp.MailOptions) error { | |||
| func (s *smtpSession) Rcpt(to string) error { | ||||
| 	logem(s.conn).Field("smtp_rcpt_to", to).Debug("RCPT TO: %s", to) | ||||
| 	return s.withFailCount(func() error { | ||||
| 		token := "" | ||||
| 		conf := s.backend.config | ||||
| 		addressList, err := mail.ParseAddressList(to) | ||||
| 		if err != nil { | ||||
|  | @ -92,18 +94,27 @@ func (s *smtpSession) Rcpt(to string) error { | |||
| 		if !strings.HasSuffix(to, "@"+conf.SMTPServerDomain) { | ||||
| 			return errInvalidDomain | ||||
| 		} | ||||
| 		// remove @ntfy.sh from end of email | ||||
| 		to = strings.TrimSuffix(to, "@"+conf.SMTPServerDomain) | ||||
| 		if conf.SMTPServerAddrPrefix != "" { | ||||
| 			if !strings.HasPrefix(to, conf.SMTPServerAddrPrefix) { | ||||
| 				return errInvalidAddress | ||||
| 			} | ||||
| 			// remove ntfy- from beginning of email | ||||
| 			to = strings.TrimPrefix(to, conf.SMTPServerAddrPrefix) | ||||
| 		} | ||||
| 		// if email contains token, split topic and token | ||||
| 		if strings.Contains(to, "+") { | ||||
| 			parts := strings.Split(to, "+") | ||||
| 			to = parts[0] | ||||
| 			token = parts[1] | ||||
| 		} | ||||
| 		if !topicRegex.MatchString(to) { | ||||
| 			return errInvalidTopic | ||||
| 		} | ||||
| 		s.mu.Lock() | ||||
| 		s.topic = to | ||||
| 		s.token = token | ||||
| 		s.mu.Unlock() | ||||
| 		return nil | ||||
| 	}) | ||||
|  | @ -177,6 +188,9 @@ func (s *smtpSession) publishMessage(m *message) error { | |||
| 	if m.Title != "" { | ||||
| 		req.Header.Set("Title", m.Title) | ||||
| 	} | ||||
| 	if s.token != "" { | ||||
| 		req.Header.Add("Authorization", "Bearer "+s.token) | ||||
| 	} | ||||
| 	rr := httptest.NewRecorder() | ||||
| 	s.backend.handler(rr, req) | ||||
| 	if rr.Code != http.StatusOK { | ||||
|  |  | |||
|  | @ -492,6 +492,27 @@ L0VOIj4KClRoaXMgaXMgYSB0ZXN0IG1lc3NhZ2UgZnJvbSBUcnVlTkFTIENPUkUuCg== | |||
| 	writeAndReadUntilLine(t, email, c, scanner, "554 5.0.0 Error: transaction failed, blame it on the weather: multipart message nested too deep") | ||||
| } | ||||
| 
 | ||||
| func TestSmtpBackend_PlaintextWithToken(t *testing.T) { | ||||
| 	email := `EHLO example.com | ||||
| MAIL FROM: phil@example.com | ||||
| RCPT TO: ntfy-mytopic+tk_KLORUqSqvNRLpY11DfkHVbHu9NGG2@ntfy.sh | ||||
| DATA | ||||
| Subject: Very short mail | ||||
| 
 | ||||
| what's up | ||||
| . | ||||
| ` | ||||
| 	s, c, _, scanner := newTestSMTPServer(t, func(w http.ResponseWriter, r *http.Request) { | ||||
| 		require.Equal(t, "/mytopic", r.URL.Path) | ||||
| 		require.Equal(t, "Very short mail", r.Header.Get("Title")) | ||||
| 		require.Equal(t, "Bearer tk_KLORUqSqvNRLpY11DfkHVbHu9NGG2", r.Header.Get("Authorization")) | ||||
| 		require.Equal(t, "what's up", readAll(t, r.Body)) | ||||
| 	}) | ||||
| 	defer s.Close() | ||||
| 	defer c.Close() | ||||
| 	writeAndReadUntilLine(t, email, c, scanner, "250 2.0.0 OK: queued") | ||||
| } | ||||
| 
 | ||||
| type smtpHandlerFunc func(http.ResponseWriter, *http.Request) | ||||
| 
 | ||||
| func newTestSMTPServer(t *testing.T, handler smtpHandlerFunc) (s *smtp.Server, c net.Conn, conf *Config, scanner *bufio.Scanner) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue