discourse_mail_receiver 4.0.7 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 621926d0206bd4c21fc7e1c138ca3674154abba678c2e12f340391821c3232f3
|
4
|
+
data.tar.gz: 746ba23e178eb0b46f88827c6da15819a956576ff4fa91d344dcd429473a04e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85da9c1a37912f5962c9ca3b7f3f297818a4f95cba651855427c67007fa1f18b70ee52a43bc301ebfc4d5d2e7f37cf33cd1624ecd14fa0615dadd688c37e8ef6
|
7
|
+
data.tar.gz: 9dfae7da9939d77675cfad66aff9f3b732d09d3d5db3b9260b0093fbaedbb7cb7c59cf7ffaef5c43f336af083887a7b425dea3a604793aabc1c255d388afca8a
|
@@ -1,12 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require
|
3
|
-
require
|
2
|
+
require "syslog"
|
3
|
+
require "json"
|
4
4
|
require "uri"
|
5
5
|
require "net/http"
|
6
|
-
require_relative
|
6
|
+
require_relative "mail_receiver_base"
|
7
7
|
|
8
8
|
class DiscourseMailReceiver < MailReceiverBase
|
9
|
-
|
10
9
|
def initialize(env_file = nil, recipient = nil, mail = nil)
|
11
10
|
super(env_file)
|
12
11
|
|
@@ -23,8 +22,8 @@ class DiscourseMailReceiver < MailReceiverBase
|
|
23
22
|
|
24
23
|
@endpoint = @env["DISCOURSE_MAIL_ENDPOINT"]
|
25
24
|
|
26
|
-
if @env[
|
27
|
-
@endpoint = "#{@env[
|
25
|
+
if @env["DISCOURSE_BASE_URL"]
|
26
|
+
@endpoint = "#{@env["DISCOURSE_BASE_URL"]}/admin/email/handle_mail"
|
28
27
|
end
|
29
28
|
@endpoint
|
30
29
|
end
|
@@ -55,5 +54,4 @@ class DiscourseMailReceiver < MailReceiverBase
|
|
55
54
|
logger.err "Failed to POST the e-mail to %s: %s", endpoint, response.code
|
56
55
|
:failure
|
57
56
|
end
|
58
|
-
|
59
57
|
end
|
@@ -1,22 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'set'
|
3
|
-
require 'syslog'
|
4
|
-
require 'json'
|
5
|
-
require 'uri'
|
6
|
-
require 'cgi'
|
7
|
-
require 'net/http'
|
8
2
|
|
9
|
-
|
10
|
-
|
3
|
+
# rubocop:disable Lint/RedundantRequireStatement
|
4
|
+
# require "set" is needed for Set
|
5
|
+
require "set"
|
6
|
+
require "syslog"
|
7
|
+
require "json"
|
8
|
+
require "uri"
|
9
|
+
require "cgi"
|
10
|
+
require "net/http"
|
11
11
|
|
12
|
-
|
12
|
+
require_relative "mail"
|
13
|
+
require_relative "mail_receiver_base"
|
13
14
|
|
15
|
+
class FastRejection < MailReceiverBase
|
14
16
|
def initialize(env_file)
|
15
17
|
super(env_file)
|
16
18
|
|
17
|
-
@disabled = @env[
|
19
|
+
@disabled = @env["DISCOURSE_FAST_REJECTION_DISABLED"] || !@env["DISCOURSE_BASE_URL"]
|
18
20
|
|
19
|
-
@blacklisted_sender_domains =
|
21
|
+
@blacklisted_sender_domains =
|
22
|
+
Set.new(@env.fetch("BLACKLISTED_SENDER_DOMAINS", "").split(" ").map(&:downcase))
|
20
23
|
end
|
21
24
|
|
22
25
|
def disabled?
|
@@ -24,7 +27,7 @@ class FastRejection < MailReceiverBase
|
|
24
27
|
end
|
25
28
|
|
26
29
|
def process
|
27
|
-
$stdout.sync = true
|
30
|
+
$stdout.sync = true # unbuffered output
|
28
31
|
|
29
32
|
args = {}
|
30
33
|
while line = gets
|
@@ -32,29 +35,29 @@ class FastRejection < MailReceiverBase
|
|
32
35
|
line = line.chomp
|
33
36
|
if line.empty?
|
34
37
|
puts "action=#{process_single_request(args)}"
|
35
|
-
puts
|
38
|
+
puts ""
|
36
39
|
|
37
|
-
args = {}
|
40
|
+
args = {} # reset for next request.
|
38
41
|
else
|
39
|
-
k, v = line.chomp.split(
|
42
|
+
k, v = line.chomp.split("=", 2)
|
40
43
|
args[k] = v
|
41
44
|
end
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
45
48
|
def process_single_request(args)
|
46
|
-
return
|
49
|
+
return "dunno" if disabled?
|
47
50
|
|
48
|
-
if args[
|
49
|
-
return
|
50
|
-
elsif args[
|
51
|
-
return
|
52
|
-
elsif args[
|
51
|
+
if args["request"] != "smtpd_access_policy"
|
52
|
+
return "defer_if_permit Internal error, Request type invalid"
|
53
|
+
elsif args["protocol_state"] != "RCPT"
|
54
|
+
return "dunno"
|
55
|
+
elsif args["sender"].nil?
|
53
56
|
# Note that while this key should always exist, its value may be the empty
|
54
57
|
# string. Postfix will convert the "<>" null sender to "".
|
55
|
-
return
|
56
|
-
elsif args[
|
57
|
-
return
|
58
|
+
return "defer_if_permit No sender specified"
|
59
|
+
elsif args["recipient"].nil?
|
60
|
+
return "defer_if_permit No recipient specified"
|
58
61
|
end
|
59
62
|
|
60
63
|
run_filters(args)
|
@@ -62,8 +65,8 @@ class FastRejection < MailReceiverBase
|
|
62
65
|
|
63
66
|
def maybe_reject_email(from, to)
|
64
67
|
uri = URI.parse(endpoint)
|
65
|
-
fromarg = CGI
|
66
|
-
toarg = CGI
|
68
|
+
fromarg = CGI.escape(from)
|
69
|
+
toarg = CGI.escape(to)
|
67
70
|
|
68
71
|
qs = "from=#{fromarg}&to=#{toarg}"
|
69
72
|
if uri.query && !uri.query.empty?
|
@@ -80,7 +83,10 @@ class FastRejection < MailReceiverBase
|
|
80
83
|
get["Api-Key"] = key
|
81
84
|
response = http.request(get)
|
82
85
|
rescue StandardError => ex
|
83
|
-
logger.err "Failed to GET smtp_should_reject answer from %s: %s (%s)",
|
86
|
+
logger.err "Failed to GET smtp_should_reject answer from %s: %s (%s)",
|
87
|
+
endpoint,
|
88
|
+
ex.message,
|
89
|
+
ex.class
|
84
90
|
logger.err ex.backtrace.map { |l| " #{l}" }.join("\n")
|
85
91
|
return "defer_if_permit Internal error, API request preparation failed"
|
86
92
|
ensure
|
@@ -89,28 +95,23 @@ class FastRejection < MailReceiverBase
|
|
89
95
|
|
90
96
|
if Net::HTTPSuccess === response
|
91
97
|
reply = JSON.parse(response.body)
|
92
|
-
if reply[
|
93
|
-
return "reject #{reply['reason']}"
|
94
|
-
end
|
98
|
+
return "reject #{reply["reason"]}" if reply["reject"]
|
95
99
|
else
|
96
100
|
logger.err "Failed to GET smtp_should_reject answer from %s: %s", endpoint, response.code
|
97
101
|
return "defer_if_permit Internal error, API request failed"
|
98
102
|
end
|
99
103
|
|
100
|
-
"dunno"
|
104
|
+
"dunno" # let future tests also be allowed to reject this one.
|
101
105
|
end
|
102
106
|
|
103
107
|
def endpoint
|
104
|
-
"#{@env[
|
108
|
+
"#{@env["DISCOURSE_BASE_URL"]}/admin/email/smtp_should_reject.json"
|
105
109
|
end
|
106
110
|
|
107
111
|
private
|
108
112
|
|
109
113
|
def run_filters(args)
|
110
|
-
filters = [
|
111
|
-
:maybe_reject_by_sender_domain,
|
112
|
-
:maybe_reject_by_api,
|
113
|
-
]
|
114
|
+
filters = %i[maybe_reject_by_sender_domain maybe_reject_by_api]
|
114
115
|
|
115
116
|
filters.each do |f|
|
116
117
|
action = send(f, args)
|
@@ -121,25 +122,24 @@ class FastRejection < MailReceiverBase
|
|
121
122
|
end
|
122
123
|
|
123
124
|
def maybe_reject_by_sender_domain(args)
|
124
|
-
sender = args[
|
125
|
+
sender = args["sender"]
|
125
126
|
|
126
127
|
return "dunno" if sender.empty?
|
127
128
|
|
128
129
|
domain = domain_from_addrspec(sender)
|
129
130
|
if domain.empty?
|
130
131
|
logger.info("deferred mail with domainless sender #{sender}")
|
131
|
-
return
|
132
|
+
return "defer_if_permit Invalid sender"
|
132
133
|
end
|
133
134
|
if @blacklisted_sender_domains.include? domain
|
134
135
|
logger.info("rejected mail from blacklisted sender domain #{domain} (from #{sender})")
|
135
|
-
return
|
136
|
+
return "reject Invalid sender"
|
136
137
|
end
|
137
138
|
|
138
139
|
"dunno"
|
139
140
|
end
|
140
141
|
|
141
142
|
def maybe_reject_by_api(args)
|
142
|
-
maybe_reject_email(args[
|
143
|
+
maybe_reject_email(args["sender"], args["recipient"])
|
143
144
|
end
|
144
|
-
|
145
145
|
end
|
@@ -1,21 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
class MailReceiverBase
|
3
|
-
class ReceiverException < StandardError
|
3
|
+
class ReceiverException < StandardError
|
4
|
+
end
|
4
5
|
|
5
6
|
attr_reader :env
|
6
7
|
|
7
8
|
def initialize(env_file)
|
8
|
-
unless File.
|
9
|
-
fatal "Config file %s does not exist. Aborting.", env_file
|
10
|
-
end
|
9
|
+
fatal "Config file %s does not exist. Aborting.", env_file unless File.exist?(env_file)
|
11
10
|
|
12
11
|
@env = JSON.parse(File.read(env_file))
|
13
12
|
|
14
|
-
%w
|
13
|
+
%w[DISCOURSE_API_KEY DISCOURSE_API_USERNAME].each do |kw|
|
15
14
|
fatal "env var %s is required", kw unless @env[kw]
|
16
15
|
end
|
17
16
|
|
18
|
-
if @env[
|
17
|
+
if @env["DISCOURSE_MAIL_ENDPOINT"].nil? && @env["DISCOURSE_BASE_URL"].nil?
|
19
18
|
fatal "DISCOURSE_MAIL_ENDPOINT and DISCOURSE_BASE_URL env var missing"
|
20
19
|
end
|
21
20
|
end
|
@@ -29,11 +28,11 @@ class MailReceiverBase
|
|
29
28
|
end
|
30
29
|
|
31
30
|
def key
|
32
|
-
@env[
|
31
|
+
@env["DISCOURSE_API_KEY"]
|
33
32
|
end
|
34
33
|
|
35
34
|
def username
|
36
|
-
@env[
|
35
|
+
@env["DISCOURSE_API_USERNAME"]
|
37
36
|
end
|
38
37
|
|
39
38
|
def fatal(*args)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: discourse_mail_receiver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0
|
4
|
+
version: 4.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Discourse Team
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mail
|
@@ -25,61 +25,89 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 2.7.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: net-smtp
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
-
type: :
|
33
|
+
version: 0.3.3
|
34
|
+
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.3.3
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rubocop-discourse
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: syntax_tree
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: syntax_tree-disable_ternary
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
81
109
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
110
|
+
version: '0'
|
83
111
|
description: A gem used to package the core .rb files of the mail-receiver.
|
84
112
|
email:
|
85
113
|
- team@discourse.org
|
@@ -95,7 +123,7 @@ homepage: https://github.com/discourse/mail-receiver
|
|
95
123
|
licenses:
|
96
124
|
- MIT
|
97
125
|
metadata: {}
|
98
|
-
post_install_message:
|
126
|
+
post_install_message:
|
99
127
|
rdoc_options: []
|
100
128
|
require_paths:
|
101
129
|
- lib
|
@@ -103,15 +131,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
131
|
requirements:
|
104
132
|
- - ">="
|
105
133
|
- !ruby/object:Gem::Version
|
106
|
-
version:
|
134
|
+
version: 3.0.0
|
107
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
136
|
requirements:
|
109
137
|
- - ">="
|
110
138
|
- !ruby/object:Gem::Version
|
111
139
|
version: '0'
|
112
140
|
requirements: []
|
113
|
-
rubygems_version: 3.
|
114
|
-
signing_key:
|
141
|
+
rubygems_version: 3.5.11
|
142
|
+
signing_key:
|
115
143
|
specification_version: 4
|
116
144
|
summary: A gem used to package the core .rb files of the mail-receiver.
|
117
145
|
test_files: []
|