logstash-input-imapraw 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 54b85a06d69130945966fee8803084ca26eaa72224f43cf7ef93b2fe4e9383a5
4
+ data.tar.gz: 555a734875551afcfdbb5efe5c5b5bd2df2e1b329e8fca452cde20200d5ed506
5
+ SHA512:
6
+ metadata.gz: c51a852d01d6796620f4b448c20ae4926bf2cc86d192642800e90e0503b71d314db24890f8bf98fa85d699978c61295b3237b012cdda3c29e3995340751e2f4c
7
+ data.tar.gz: 86def1fa25c92ed4dfadd1195daf8d5f6626c855c4152cdf67de80a67c3b3f3710800482e8cae1f88b77ddfca155a0ba99f0895021cee032498145c93d6731ce
data/CHANGELOG.md ADDED
@@ -0,0 +1,35 @@
1
+ ## 3.1.0
2
+ - Adds an option to recursively search the message parts for attachment and inline attachment filenames. If the save_attachments option is set to true, the content of attachments is included in the `attachments.data` field. The attachment data can then be used by the Elasticsearch Ingest Attachment Processor Plugin.
3
+ [#48](https://github.com/logstash-plugins/logstash-input-imap/pull/48)
4
+
5
+ ## 3.0.7
6
+ - Added facility to use IMAP uid to retrieve new mails instead of "NOT SEEN" [#36](https://github.com/logstash-plugins/logstash-input-imap/pull/36)
7
+
8
+ ## 3.0.6
9
+ - Docs: Set the default_codec doc attribute.
10
+
11
+ ## 3.0.5
12
+ - Update gemspec summary
13
+
14
+ ## 3.0.4
15
+ - Fix some documentation issues
16
+
17
+ ## 3.0.2
18
+ - Relax constraint on logstash-core-plugin-api to >= 1.60 <= 2.99
19
+
20
+ ## 3.0.1
21
+ - Republish all the gems under jruby.
22
+ ## 3.0.0
23
+ - Update the plugin to the version 2.0 of the plugin api, this change is required for Logstash 5.0 compatibility. See https://github.com/elastic/logstash/issues/5141
24
+ # 2.0.5
25
+ - Depend on logstash-core-plugin-api instead of logstash-core, removing the need to mass update plugins on major releases of logstash
26
+ # 2.0.4
27
+ - New dependency requirements for logstash-core for the 5.0 release
28
+ ## 2.0.3
29
+ - Fixed fields assignments
30
+
31
+ ## 2.0.0
32
+ - Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
33
+ instead of using Thread.raise on the plugins' threads. Ref: https://github.com/elastic/logstash/pull/3895
34
+ - Dependency on logstash-core update to 2.0
35
+
data/CONTRIBUTORS ADDED
@@ -0,0 +1,23 @@
1
+ The following is a list of people who have contributed ideas, code, bug
2
+ reports, or in general have helped logstash along its way.
3
+
4
+ Contributors:
5
+ * Aaron Mildenstein (untergeek)
6
+ * Bernd Ahlers (bernd)
7
+ * Brad Fritz (bfritz)
8
+ * Colin Surprenant (colinsurprenant)
9
+ * Jason Kendall (coolacid)
10
+ * Jonathan Van Eenwyk (jdve)
11
+ * Jordan Sissel (jordansissel)
12
+ * Philippe Weber (wiibaa)
13
+ * Pier-Hugues Pellerin (ph)
14
+ * Raffael Schmid (luxflux)
15
+ * Richard Pijnenburg (electrical)
16
+ * Sam Doran (samdoran)
17
+ * Sverre Bakke (sbakke)
18
+ * herver (herver)
19
+
20
+ Note: If you've sent us patches, bug reports, or otherwise contributed to
21
+ Logstash, and you aren't on the list above and want to be, please let us know
22
+ and we'll make sure you're here. Contributions from folks like you are what make
23
+ open source awesome.
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ logstash_path = ENV["LOGSTASH_PATH"] || "../../logstash"
6
+ use_logstash_source = ENV["LOGSTASH_SOURCE"] && ENV["LOGSTASH_SOURCE"].to_s == "1"
7
+
8
+ if Dir.exist?(logstash_path) && use_logstash_source
9
+ gem 'logstash-core', :path => "#{logstash_path}/logstash-core"
10
+ gem 'logstash-core-plugin-api', :path => "#{logstash_path}/logstash-core-plugin-api"
11
+ end
data/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright 2020 Elastic and contributors
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
data/NOTICE.TXT ADDED
@@ -0,0 +1,5 @@
1
+ Elasticsearch
2
+ Copyright 2012-2015 Elasticsearch
3
+
4
+ This product includes software developed by The Apache Software
5
+ Foundation (http://www.apache.org/).
data/README.md ADDED
@@ -0,0 +1 @@
1
+ This is a fork of the logstash plugin that adds a new boolean configuration parameter `save_full_message`, which will not attempt to parse the body of the message and instead save the content without alteration, and the raw bytes to `raw`
@@ -0,0 +1,215 @@
1
+ :plugin: imap
2
+ :type: input
3
+ :default_codec: plain
4
+
5
+ ///////////////////////////////////////////
6
+ START - GENERATED VARIABLES, DO NOT EDIT!
7
+ ///////////////////////////////////////////
8
+ :version: %VERSION%
9
+ :release_date: %RELEASE_DATE%
10
+ :changelog_url: %CHANGELOG_URL%
11
+ :include_path: ../../../../logstash/docs/include
12
+ ///////////////////////////////////////////
13
+ END - GENERATED VARIABLES, DO NOT EDIT!
14
+ ///////////////////////////////////////////
15
+
16
+ [id="plugins-{type}s-{plugin}"]
17
+
18
+ === Imap input plugin
19
+
20
+ include::{include_path}/plugin_header.asciidoc[]
21
+
22
+ ==== Description
23
+
24
+ Read mails from IMAP server
25
+
26
+ Periodically scan an IMAP folder (`INBOX` by default) and move any read messages
27
+ to the trash.
28
+
29
+ [id="plugins-{type}s-{plugin}-options"]
30
+ ==== Imap Input Configuration Options
31
+
32
+ This plugin supports the following configuration options plus the <<plugins-{type}s-{plugin}-common-options>> described later.
33
+
34
+ [cols="<,<,<",options="header",]
35
+ |=======================================================================
36
+ |Setting |Input type|Required
37
+ | <<plugins-{type}s-{plugin}-check_interval>> |<<number,number>>|No
38
+ | <<plugins-{type}s-{plugin}-content_type>> |<<string,string>>|No
39
+ | <<plugins-{type}s-{plugin}-delete>> |<<boolean,boolean>>|No
40
+ | <<plugins-{type}s-{plugin}-expunge>> |<<boolean,boolean>>|No
41
+ | <<plugins-{type}s-{plugin}-fetch_count>> |<<number,number>>|No
42
+ | <<plugins-{type}s-{plugin}-folder>> |<<string,string>>|No
43
+ | <<plugins-{type}s-{plugin}-host>> |<<string,string>>|Yes
44
+ | <<plugins-{type}s-{plugin}-lowercase_headers>> |<<boolean,boolean>>|No
45
+ | <<plugins-{type}s-{plugin}-password>> |<<password,password>>|Yes
46
+ | <<plugins-{type}s-{plugin}-port>> |<<number,number>>|No
47
+ | <<plugins-{type}s-{plugin}-save_attachments>> |<<boolean,boolean>>|No
48
+ | <<plugins-{type}s-{plugin}-secure>> |<<boolean,boolean>>|No
49
+ | <<plugins-{type}s-{plugin}-sincedb_path>> |<<string,string>>|No
50
+ | <<plugins-{type}s-{plugin}-strip_attachments>> |<<boolean,boolean>>|No
51
+ | <<plugins-{type}s-{plugin}-uid_tracking>> |<<boolean,boolean>>|No
52
+ | <<plugins-{type}s-{plugin}-user>> |<<string,string>>|Yes
53
+ | <<plugins-{type}s-{plugin}-verify_cert>> |<<boolean,boolean>>|No
54
+ |=======================================================================
55
+
56
+ Also see <<plugins-{type}s-{plugin}-common-options>> for a list of options supported by all
57
+ input plugins.
58
+
59
+ &nbsp;
60
+
61
+ [id="plugins-{type}s-{plugin}-check_interval"]
62
+ ===== `check_interval`
63
+
64
+ * Value type is <<number,number>>
65
+ * Default value is `300`
66
+
67
+
68
+
69
+ [id="plugins-{type}s-{plugin}-content_type"]
70
+ ===== `content_type`
71
+
72
+ * Value type is <<string,string>>
73
+ * Default value is `"text/plain"`
74
+
75
+ For multipart messages, use the first part that has this
76
+ content-type as the event message.
77
+
78
+ [id="plugins-{type}s-{plugin}-delete"]
79
+ ===== `delete`
80
+
81
+ * Value type is <<boolean,boolean>>
82
+ * Default value is `false`
83
+
84
+
85
+
86
+ [id="plugins-{type}s-{plugin}-expunge"]
87
+ ===== `expunge`
88
+
89
+ * Value type is <<boolean,boolean>>
90
+ * Default value is `false`
91
+
92
+
93
+
94
+ [id="plugins-{type}s-{plugin}-fetch_count"]
95
+ ===== `fetch_count`
96
+
97
+ * Value type is <<number,number>>
98
+ * Default value is `50`
99
+
100
+
101
+
102
+ [id="plugins-{type}s-{plugin}-folder"]
103
+ ===== `folder`
104
+
105
+ * Value type is <<string,string>>
106
+ * Default value is `"INBOX"`
107
+
108
+
109
+
110
+ [id="plugins-{type}s-{plugin}-host"]
111
+ ===== `host`
112
+
113
+ * This is a required setting.
114
+ * Value type is <<string,string>>
115
+ * There is no default value for this setting.
116
+
117
+
118
+
119
+ [id="plugins-{type}s-{plugin}-lowercase_headers"]
120
+ ===== `lowercase_headers`
121
+
122
+ * Value type is <<boolean,boolean>>
123
+ * Default value is `true`
124
+
125
+
126
+
127
+ [id="plugins-{type}s-{plugin}-password"]
128
+ ===== `password`
129
+
130
+ * This is a required setting.
131
+ * Value type is <<password,password>>
132
+ * There is no default value for this setting.
133
+
134
+
135
+
136
+ [id="plugins-{type}s-{plugin}-port"]
137
+ ===== `port`
138
+
139
+ * Value type is <<number,number>>
140
+ * There is no default value for this setting.
141
+
142
+ [id="plugins-{type}s-{plugin}-save_attachments"]
143
+ ===== `save_attachments`
144
+
145
+ * Value type is <<boolean,boolean>>
146
+ * Default value is `false`
147
+
148
+ When set to true the content of attachments will be included in the `attachments.data` field.
149
+
150
+ [id="plugins-{type}s-{plugin}-secure"]
151
+ ===== `secure`
152
+
153
+ * Value type is <<boolean,boolean>>
154
+ * Default value is `true`
155
+
156
+ [id="plugins-{type}s-{plugin}-sincedb_path"]
157
+ ===== `sincedb_path`
158
+
159
+ * Value type is <<string,string>>
160
+ * There is no default value for this setting.
161
+
162
+ Path of the sincedb database file (keeps track of the UID of the last processed
163
+ mail) that will be written to disk. The default will write sincedb file to
164
+ `<path.data>/plugins/inputs/imap` directory.
165
+ NOTE: it must be a file path and not a directory path.
166
+
167
+ [id="plugins-{type}s-{plugin}-strip_attachments"]
168
+ ===== `strip_attachments`
169
+
170
+ * Value type is <<boolean,boolean>>
171
+ * Default value is `false`
172
+
173
+
174
+
175
+ [id="plugins-{type}s-{plugin}-uid_tracking"]
176
+ ===== `uid_tracking`
177
+
178
+ * Value type is <<boolean,boolean>>
179
+ * Default value is `false`
180
+
181
+ When the IMAP input plugin connects to the mailbox for the first time and
182
+ the UID of the last processed mail is not yet known, the unread mails are
183
+ first downloaded and the UID of the last processed mail is saved. From
184
+ this point on, if `uid_tracking` is set to `true`, all new mail will be
185
+ downloaded regardless of whether they are marked as read or unread. This
186
+ allows users or other services to use the mailbox simultaneously with the
187
+ IMAP input plugin. UID of the last processed mail is always saved regardles
188
+ of the `uid_tracking` value, so you can switch its value as needed. In
189
+ transition from the previous IMAP input plugin version, first process at least
190
+ one mail with `uid_tracking` set to `false` to save the UID of the last
191
+ processed mail and then switch `uid_tracking` to `true`.
192
+
193
+ [id="plugins-{type}s-{plugin}-user"]
194
+ ===== `user`
195
+
196
+ * This is a required setting.
197
+ * Value type is <<string,string>>
198
+ * There is no default value for this setting.
199
+
200
+
201
+
202
+ [id="plugins-{type}s-{plugin}-verify_cert"]
203
+ ===== `verify_cert`
204
+
205
+ * Value type is <<boolean,boolean>>
206
+ * Default value is `true`
207
+
208
+
209
+
210
+
211
+
212
+ [id="plugins-{type}s-{plugin}-common-options"]
213
+ include::{include_path}/{type}.asciidoc[]
214
+
215
+ :default_codec!:
@@ -0,0 +1,245 @@
1
+ # encoding: utf-8
2
+ require "logstash/inputs/base"
3
+ require "logstash/namespace"
4
+ require "logstash/timestamp"
5
+ require "stud/interval"
6
+ require "socket" # for Socket.gethostname
7
+
8
+ # Read mails from IMAP server
9
+ #
10
+ # Periodically scan an IMAP folder (`INBOX` by default) and move any read messages
11
+ # to the trash.
12
+ class LogStash::Inputs::IMAPRAW < LogStash::Inputs::Base
13
+ config_name "imap"
14
+
15
+ default :codec, "plain"
16
+
17
+ config :host, :validate => :string, :required => true
18
+ config :port, :validate => :number
19
+
20
+ config :user, :validate => :string, :required => true
21
+ config :password, :validate => :password, :required => true
22
+ config :secure, :validate => :boolean, :default => true
23
+ config :verify_cert, :validate => :boolean, :default => true
24
+
25
+ config :folder, :validate => :string, :default => 'INBOX'
26
+ config :fetch_count, :validate => :number, :default => 50
27
+ config :lowercase_headers, :validate => :boolean, :default => true
28
+ config :check_interval, :validate => :number, :default => 300
29
+ config :delete, :validate => :boolean, :default => false
30
+ config :expunge, :validate => :boolean, :default => false
31
+ config :strip_attachments, :validate => :boolean, :default => false
32
+ config :save_attachments, :validate => :boolean, :default => false
33
+ config :save_full_message, :validate => :boolean, :default => false
34
+
35
+ # For multipart messages, use the first part that has this
36
+ # content-type as the event message.
37
+ config :content_type, :validate => :string, :default => "text/plain"
38
+
39
+ # Whether to use IMAP uid to track last processed message
40
+ config :uid_tracking, :validate => :boolean, :default => false
41
+
42
+ # Path to file with last run time metadata
43
+ config :sincedb_path, :validate => :string, :required => false
44
+
45
+ def register
46
+ require "net/imap" # in stdlib
47
+ require "mail" # gem 'mail'
48
+
49
+ if @secure and not @verify_cert
50
+ @logger.warn("Running IMAP without verifying the certificate may grant attackers unauthorized access to your mailbox or data")
51
+ end
52
+
53
+ if @port.nil?
54
+ if @secure
55
+ @port = 993
56
+ else
57
+ @port = 143
58
+ end
59
+ end
60
+
61
+ # Load last processed IMAP uid from file if exists
62
+ if @sincedb_path.nil?
63
+ datapath = File.join(LogStash::SETTINGS.get_value("path.data"), "plugins", "inputs", "imap")
64
+ # Ensure that the filepath exists before writing, since it's deeply nested.
65
+ FileUtils::mkdir_p datapath
66
+ @sincedb_path = File.join(datapath, ".sincedb_" + Digest::MD5.hexdigest("#{@user}_#{@host}_#{@port}_#{@folder}"))
67
+ end
68
+ if File.directory?(@sincedb_path)
69
+ raise ArgumentError.new("The \"sincedb_path\" argument must point to a file, received a directory: \"#{@sincedb_path}\"")
70
+ end
71
+ @logger.info("Using \"sincedb_path\": \"#{@sincedb_path}\"")
72
+ if File.exist?(@sincedb_path)
73
+ @uid_last_value = File.read(@sincedb_path).to_i
74
+ @logger.info("Loading \"uid_last_value\": \"#{@uid_last_value}\"")
75
+ end
76
+
77
+ @content_type_re = Regexp.new("^" + @content_type)
78
+ end # def register
79
+
80
+ def connect
81
+ sslopt = @secure
82
+ if @secure and not @verify_cert
83
+ sslopt = { :verify_mode => OpenSSL::SSL::VERIFY_NONE }
84
+ end
85
+ imap = Net::IMAP.new(@host, :port => @port, :ssl => sslopt)
86
+ imap.login(@user, @password.value)
87
+ return imap
88
+ end
89
+
90
+ def run(queue)
91
+ @run_thread = Thread.current
92
+ Stud.interval(@check_interval) do
93
+ check_mail(queue)
94
+ end
95
+ end
96
+
97
+ def check_mail(queue)
98
+ # TODO(sissel): handle exceptions happening during runtime:
99
+ # EOFError, OpenSSL::SSL::SSLError
100
+ imap = connect
101
+ imap.select(@folder)
102
+ if @uid_tracking && @uid_last_value
103
+ # If there are no new messages, uid_search returns @uid_last_value
104
+ # because it is the last message, so we need to delete it.
105
+ ids = imap.uid_search(["UID", (@uid_last_value+1..-1)]).delete_if { |uid|
106
+ uid <= @uid_last_value
107
+ }
108
+ else
109
+ ids = imap.uid_search("NOT SEEN")
110
+ end
111
+
112
+ ids.each_slice(@fetch_count) do |id_set|
113
+ items = imap.uid_fetch(id_set, ["BODY.PEEK[]", "UID"])
114
+ items.each do |item|
115
+ next unless item.attr.has_key?("BODY[]")
116
+ mail = Mail.read_from_string(item.attr["BODY[]"])
117
+ if @strip_attachments
118
+ queue << parse_mail(mail.without_attachments!, item)
119
+ elsif @save_full_message
120
+ queue << parse_mail(mail, item)
121
+ else
122
+ queue << parse_mail(mail, item)
123
+ end
124
+ # Mark message as processed
125
+ @uid_last_value = item.attr["UID"]
126
+ imap.uid_store(@uid_last_value, '+FLAGS', @delete || @expunge ? :Deleted : :Seen)
127
+
128
+ # Stop message processing if it is requested
129
+ break if stop?
130
+ end
131
+
132
+ # Expunge deleted messages
133
+ imap.expunge() if @expunge
134
+
135
+ # Stop message fetching if it is requested
136
+ break if stop?
137
+ end
138
+
139
+ rescue => e
140
+ @logger.error("Encountered error #{e.class}", :message => e.message, :backtrace => e.backtrace)
141
+ # Do not raise error, check_mail will be invoked in the next run time
142
+
143
+ ensure
144
+ # Close the connection (and ignore errors)
145
+ imap.close rescue nil
146
+ imap.disconnect rescue nil
147
+
148
+ # Always save @uid_last_value so when tracking is switched from
149
+ # "NOT SEEN" to "UID" we will continue from first unprocessed message
150
+ if @uid_last_value
151
+ @logger.info("Saving \"uid_last_value\": \"#{@uid_last_value}\"")
152
+ File.write(@sincedb_path, @uid_last_value)
153
+ end
154
+ end
155
+
156
+ def parse_attachments(mail)
157
+ attachments = []
158
+ mail.attachments.each do |attachment|
159
+ if @save_attachments
160
+ attachments << { "filename" => attachment.filename, "data" => attachment.body.encoded }
161
+ else
162
+ attachments << { "filename" => attachment.filename}
163
+ end
164
+ end
165
+ return attachments
166
+ end
167
+
168
+ def parse_mail(mail, item)
169
+ # Add a debug message so we can track what message might cause an error later
170
+ @logger.debug? && @logger.debug("Working with message_id", :message_id => mail.message_id)
171
+ # TODO(sissel): What should a multipart message look like as an event?
172
+ # For now, just take the plain-text part and set it as the message.
173
+ if mail.parts.count == 0
174
+ # No multipart message, just use the body as the event text
175
+ message = mail.body.decoded
176
+ else
177
+ # Multipart message; use the first text/plain part we find
178
+ part = mail.parts.find { |p| p.content_type.match @content_type_re } || mail.parts.first
179
+ message = part.decoded
180
+
181
+ # Parse attachments
182
+ attachments = parse_attachments(mail)
183
+ end
184
+
185
+ @codec.decode(message) do |event|
186
+ # Use the 'Date' field as the timestamp
187
+ event.timestamp = LogStash::Timestamp.new(mail.date.to_time)
188
+
189
+ # Add fields: Add message.header_fields { |h| h.name=> h.value }
190
+ mail.header_fields.each do |header|
191
+ # 'header.name' can sometimes be a Mail::Multibyte::Chars, get it in String form
192
+ name = @lowercase_headers ? header.name.to_s.downcase : header.name.to_s
193
+ # Call .decoded on the header in case it's in encoded-word form.
194
+ # Details at:
195
+ # https://github.com/mikel/mail/blob/master/README.md#encodings
196
+ # http://tools.ietf.org/html/rfc2047#section-2
197
+ value = transcode_to_utf8(header.decoded.to_s)
198
+
199
+ # Assume we already processed the 'date' above.
200
+ next if name == "Date"
201
+
202
+ case (field = event.get(name))
203
+ when String
204
+ # promote string to array if a header appears multiple times
205
+ # (like 'received')
206
+ event.set(name, [field, value])
207
+ when Array
208
+ field << value
209
+ event.set(name, field)
210
+ when nil
211
+ event.set(name, value)
212
+ end
213
+ end
214
+
215
+ # Add attachments
216
+ if attachments && attachments.length > 0
217
+ event.set('attachments', attachments)
218
+ end
219
+
220
+ #Add Raw Body if configured
221
+ if @save_full_message
222
+ event.set('raw_message_body',item.attr["BODY[]"])
223
+ end
224
+
225
+ decorate(event)
226
+ event
227
+ end
228
+ end
229
+
230
+ def stop
231
+ Stud.stop!(@run_thread)
232
+ $stdin.close
233
+ end
234
+
235
+ private
236
+
237
+ # transcode_to_utf8 is meant for headers transcoding.
238
+ # the mail gem will set the correct encoding on header strings decoding
239
+ # and we want to transcode it to utf8
240
+ def transcode_to_utf8(s)
241
+ unless s.nil?
242
+ s.encode(Encoding::UTF_8, :invalid => :replace, :undef => :replace)
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,31 @@
1
+ Gem::Specification.new do |s|
2
+
3
+ s.name = 'logstash-input-imapraw'
4
+ s.version = '1.0.5'
5
+ s.licenses = ['Apache License (2.0)']
6
+ s.summary = "Reads mail from an IMAP server and publishes the raw body as well as the decoded body"
7
+ s.description = "This is a fork with added functionality - This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
8
+ s.authors = ["Dustin Hawkins"]
9
+ s.email = 'dhawkins@resultsgeneration.com'
10
+ s.homepage = "http://github.com/dustin-hawkins/logstash-input-imapraw"
11
+ s.require_paths = ["lib"]
12
+
13
+ # Files
14
+ s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "docs/**/*"]
15
+
16
+ # Tests
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+
19
+ # Special flag to let us know this is actually a logstash plugin
20
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "input" }
21
+
22
+ # Gem dependencies
23
+ s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
24
+ s.add_runtime_dependency 'logstash-codec-plain'
25
+ s.add_runtime_dependency 'mail', '~> 2.6.3'
26
+ s.add_runtime_dependency 'mime-types', '2.6.2'
27
+ s.add_runtime_dependency 'stud', '~> 0.0.22'
28
+
29
+ s.add_development_dependency 'logstash-devutils'
30
+ s.add_development_dependency 'insist'
31
+ end
@@ -0,0 +1,173 @@
1
+ # encoding: utf-8
2
+ require "logstash/devutils/rspec/spec_helper"
3
+ require "insist"
4
+ require "logstash/devutils/rspec/shared_examples"
5
+ require "logstash/inputs/imap"
6
+ require "mail"
7
+ require "net/imap"
8
+ require "base64"
9
+
10
+
11
+ describe LogStash::Inputs::IMAPRAW do
12
+
13
+ context "when interrupting the plugin" do
14
+ it_behaves_like "an interruptible input plugin" do
15
+ let(:config) do
16
+ { "type" => "imap",
17
+ "host" => "localhost",
18
+ "user" => "logstash",
19
+ "password" => "secret" }
20
+ end
21
+ let(:imap) { double("imap") }
22
+ let(:ids) { double("ids") }
23
+ before(:each) do
24
+ allow(imap).to receive(:login)
25
+ allow(imap).to receive(:select)
26
+ allow(imap).to receive(:close)
27
+ allow(imap).to receive(:disconnect)
28
+ allow(imap).to receive(:store)
29
+ allow(ids).to receive(:each_slice).and_return([])
30
+
31
+ allow(imap).to receive(:uid_search).with("NOT SEEN").and_return(ids)
32
+ allow(Net::IMAP).to receive(:new).and_return(imap)
33
+ end
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ describe LogStash::Inputs::IMAPRAW do
40
+ user = "logstash"
41
+ password = "secret"
42
+ msg_time = Time.new
43
+ msg_text = "foo\nbar\nbaz"
44
+ msg_html = "<p>a paragraph</p>\n\n"
45
+ msg_binary = "\x42\x43\x44"
46
+ msg_unencoded = "raw text 🐐"
47
+
48
+ subject do
49
+ Mail.new do
50
+ from "me@example.com"
51
+ to "you@example.com"
52
+ subject "logstash imap input test"
53
+ date msg_time
54
+ body msg_text
55
+ add_file :filename => "some.html", :content => msg_html
56
+ add_file :filename => "image.png", :content => msg_binary
57
+ add_file :filename => "unencoded.data", :content => msg_unencoded, :content_transfer_encoding => "7bit"
58
+ end
59
+ end
60
+
61
+ context "with both text and html parts" do
62
+ context "when no content-type selected" do
63
+ it "should select text/plain part" do
64
+ config = {"type" => "imap", "host" => "localhost",
65
+ "user" => "#{user}", "password" => "#{password}"}
66
+
67
+ input = LogStash::Inputs::IMAPRAW.new config
68
+ input.register
69
+ event = input.parse_mail(subject, nil)
70
+ insist { event.get("message") } == msg_text
71
+ end
72
+ end
73
+
74
+ context "when text/html content-type selected" do
75
+ it "should select text/html part" do
76
+ config = {"type" => "imap", "host" => "localhost",
77
+ "user" => "#{user}", "password" => "#{password}",
78
+ "content_type" => "text/html"}
79
+
80
+ input = LogStash::Inputs::IMAPRAW.new config
81
+ input.register
82
+ event = input.parse_mail(subject, nil)
83
+ insist { event.get("message") } == msg_html
84
+ end
85
+ end
86
+ end
87
+
88
+ context "when subject is in RFC 2047 encoded-word format" do
89
+ it "should be decoded" do
90
+ subject.subject = "=?iso-8859-1?Q?foo_:_bar?="
91
+ config = {"type" => "imap", "host" => "localhost",
92
+ "user" => "#{user}", "password" => "#{password}"}
93
+
94
+ input = LogStash::Inputs::IMAPRAW.new config
95
+ input.register
96
+ event = input.parse_mail(subject, nil)
97
+ insist { event.get("subject") } == "foo : bar"
98
+ end
99
+ end
100
+
101
+ context "with multiple values for same header" do
102
+ it "should add 2 values as array in event" do
103
+ subject.received = "test1"
104
+ subject.received = "test2"
105
+
106
+ config = {"type" => "imap", "host" => "localhost",
107
+ "user" => "#{user}", "password" => "#{password}"}
108
+
109
+ input = LogStash::Inputs::IMAPRAW.new config
110
+ input.register
111
+ event = input.parse_mail(subject, nil)
112
+ insist { event.get("received") } == ["test1", "test2"]
113
+ end
114
+
115
+ it "should add more than 2 values as array in event" do
116
+ subject.received = "test1"
117
+ subject.received = "test2"
118
+ subject.received = "test3"
119
+
120
+ config = {"type" => "imap", "host" => "localhost",
121
+ "user" => "#{user}", "password" => "#{password}"}
122
+
123
+ input = LogStash::Inputs::IMAPRAW.new config
124
+ input.register
125
+ event = input.parse_mail(subject, nil)
126
+ insist { event.get("received") } == ["test1", "test2", "test3"]
127
+ end
128
+ end
129
+
130
+ context "when a header field is nil" do
131
+ it "should parse mail" do
132
+ subject.header['X-Custom-Header'] = nil
133
+ config = {"type" => "imap", "host" => "localhost",
134
+ "user" => "#{user}", "password" => "#{password}"}
135
+
136
+ input = LogStash::Inputs::IMAPRAW.new config
137
+ input.register
138
+ event = input.parse_mail(subject, nil)
139
+ insist { event.get("message") } == msg_text
140
+ end
141
+ end
142
+
143
+ context "with attachments" do
144
+ it "should extract filenames" do
145
+ config = {"type" => "imap", "host" => "localhost",
146
+ "user" => "#{user}", "password" => "#{password}"}
147
+
148
+ input = LogStash::Inputs::IMAPRAW.new config
149
+ input.register
150
+ event = input.parse_mail(subject, nil)
151
+ insist { event.get("attachments") } == [
152
+ {"filename"=>"some.html"},
153
+ {"filename"=>"image.png"},
154
+ {"filename"=>"unencoded.data"}
155
+ ]
156
+ end
157
+
158
+ it "should extract the encoded content" do
159
+ config = {"type" => "imap", "host" => "localhost",
160
+ "user" => "#{user}", "password" => "#{password}",
161
+ "save_attachments" => true}
162
+
163
+ input = LogStash::Inputs::IMAPRAW.new config
164
+ input.register
165
+ event = input.parse_mail(subject, nil)
166
+ insist { event.get("attachments") } == [
167
+ {"data"=> Base64.encode64(msg_html).encode(crlf_newline: true), "filename"=>"some.html"},
168
+ {"data"=> Base64.encode64(msg_binary).encode(crlf_newline: true), "filename"=>"image.png"},
169
+ {"data"=> msg_unencoded, "filename"=>"unencoded.data"}
170
+ ]
171
+ end
172
+ end
173
+ end
metadata ADDED
@@ -0,0 +1,163 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-input-imapraw
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.5
5
+ platform: ruby
6
+ authors:
7
+ - Dustin Hawkins
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-06-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: logstash-core-plugin-api
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.60'
20
+ - - "<="
21
+ - !ruby/object:Gem::Version
22
+ version: '2.99'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1.60'
30
+ - - "<="
31
+ - !ruby/object:Gem::Version
32
+ version: '2.99'
33
+ - !ruby/object:Gem::Dependency
34
+ name: logstash-codec-plain
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: mail
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 2.6.3
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 2.6.3
61
+ - !ruby/object:Gem::Dependency
62
+ name: mime-types
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '='
66
+ - !ruby/object:Gem::Version
67
+ version: 2.6.2
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '='
73
+ - !ruby/object:Gem::Version
74
+ version: 2.6.2
75
+ - !ruby/object:Gem::Dependency
76
+ name: stud
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 0.0.22
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 0.0.22
89
+ - !ruby/object:Gem::Dependency
90
+ name: logstash-devutils
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: insist
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ description: This is a fork with added functionality - This gem is a Logstash plugin
118
+ required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin
119
+ install gemname. This gem is not a stand-alone program
120
+ email: dhawkins@resultsgeneration.com
121
+ executables: []
122
+ extensions: []
123
+ extra_rdoc_files: []
124
+ files:
125
+ - CHANGELOG.md
126
+ - CONTRIBUTORS
127
+ - Gemfile
128
+ - LICENSE
129
+ - NOTICE.TXT
130
+ - README.md
131
+ - docs/index.asciidoc
132
+ - lib/logstash/inputs/imap.rb
133
+ - logstash-input-imapraw.gemspec
134
+ - spec/inputs/imap_spec.rb
135
+ homepage: http://github.com/dustin-hawkins/logstash-input-imapraw
136
+ licenses:
137
+ - Apache License (2.0)
138
+ metadata:
139
+ logstash_plugin: 'true'
140
+ logstash_group: input
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ requirements: []
156
+ rubyforge_project:
157
+ rubygems_version: 2.7.6
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: Reads mail from an IMAP server and publishes the raw body as well as the
161
+ decoded body
162
+ test_files:
163
+ - spec/inputs/imap_spec.rb