carterdte_smtp_filter 0.0.3

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bf26a99cf494c091ab984734d04020553fd7cbe2
4
+ data.tar.gz: cc6a525a307cabb04baee63c654f9705a3f5869d
5
+ SHA512:
6
+ metadata.gz: 067f9613141e0dbca9111bc38913797f8fbbea550ee511e752eccb64367f5dc07ebeb5218f27096370997d8a6e0ae0fd57a0d43e80fa42259ea9d7535946135e
7
+ data.tar.gz: bbe85d37804f6565dce72353a6a9de274947f5a69b628c1ef7c31d69cd161ee98a45756f07f4c4f310db12118b06e4f84d6bae01323db3f85f68a2c36a2373b8
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in carterdte_smtp_filter.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Patricio Bruna
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # CarterdteSmtpFilter
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'carterdte_smtp_filter'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install carterdte_smtp_filter
18
+
19
+ ## Configuration
20
+
21
+ ```yaml
22
+ bind_address: 127.0.0.1
23
+ bind_port: 30024
24
+ return_host: 127.0.0.1
25
+ return_port: 30025
26
+ max_connections: 10
27
+ elasticsearch_host: 127.0.0.1
28
+ elasticsearch_port: 9200
29
+ api_user: pbruna@example.com
30
+ api_password: 123456
31
+ api_host: "api.dte.zboxapp.com"
32
+ log_file: "./test/tmp/carterdte_smtp_filter.log"
33
+ stand_alone: ""
34
+ ```
35
+
36
+ ## Contributing
37
+
38
+ 1. Fork it ( https://github.com/[my-github-username]/carterdte_smtp_filter/fork )
39
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
40
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
41
+ 4. Push to the branch (`git push origin my-new-feature`)
42
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |task|
5
+ task.libs << %w(test lib)
6
+ task.pattern = 'test/test_*.rb'
7
+ end
8
+
9
+ task :default => :test
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'carterdte_smtp_filter'
5
+ require 'optparse'
6
+
7
+ # Parsing options
8
+ ARGV << '-h' if ARGV.empty?
9
+
10
+ options = {}
11
+
12
+ optparse = OptionParser.new do |opts|
13
+
14
+ opts.banner = "Usage: carterdte_smtp_filter --config [YAML Config File]"
15
+
16
+ opts.on("-cCONFIG", "--config=CONFIG", "Yaml Config File") do |o|
17
+ options[:config] = o
18
+ end
19
+
20
+ opts.on("-h", "--help", "Prints this help") do
21
+ puts opts
22
+ exit
23
+ end
24
+
25
+ end
26
+
27
+ optparse.parse!
28
+ # We load the configuration
29
+ if options[:config]
30
+ CarterdteSmtpFilter::Config.parse(options[:config])
31
+
32
+ logger = CarterdteSmtpFilter.logger
33
+ logger.info("#{Time.now}: Starting CarterDte SMTP Filter")
34
+
35
+ # Create a new server instance
36
+ server = CarterdteSmtpFilter::SmtpServer.new()
37
+
38
+ # Start the server
39
+ server.start
40
+
41
+ # Wait a second
42
+ sleep 1
43
+
44
+ # Run forever and ever
45
+ server.join
46
+
47
+ # setup exit code
48
+
49
+ end
50
+ BEGIN {
51
+ at_exit {
52
+ # check to shutdown connection
53
+ if server
54
+ # Output for debug
55
+ puts("#{Time.now}: Shutdown CarterDte SMTP Filter...")
56
+ # gracefully connections down
57
+ server.shutdown
58
+ # check once if some connection(s) need(s) more time
59
+ sleep 2 unless server.connections == 0
60
+ # stop all threads and connections
61
+ server.stop
62
+ puts("#{Time.now}: CarterDte SMTP Filter down!")
63
+ end
64
+ # Output for debug
65
+ }
66
+ }
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'carterdte_smtp_filter/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "carterdte_smtp_filter"
8
+ spec.version = CarterdteSmtpFilter::VERSION
9
+ spec.authors = ["Patricio Bruna"]
10
+ spec.email = ["pbruna@gmail.com"]
11
+ spec.summary = "Postfix SMTP Filter to parse DTE files to CarterDTE Platform"
12
+ spec.description = "Description - #{spec.summary}"
13
+ spec.homepage = "https://github.com/ZBoxApp/carterdte_smtp_filter"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'mail', "~> 2.6"
22
+ spec.add_dependency "midi-smtp-server", "~> 2.0"
23
+ spec.add_dependency 'xml-simple', "~> 1.1"
24
+ spec.add_dependency "rest-client", "~> 1.7"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.6"
27
+ spec.add_development_dependency "rake", "~> 10.4"
28
+ spec.add_development_dependency "guard", "~> 2.12"
29
+ spec.add_development_dependency "guard-minitest", "~> 2.4"
30
+ spec.add_development_dependency "minitest-reporters", "~> 1.0"
31
+ spec.add_development_dependency "sinatra", "~> 1.4"
32
+ spec.add_development_dependency "webmock", "~> 1.20"
33
+ end
@@ -0,0 +1,27 @@
1
+ require "midi-smtp-server"
2
+ require "mail"
3
+ require 'json'
4
+ require 'xmlsimple'
5
+ require 'time'
6
+ require 'date'
7
+ require 'logger'
8
+ require 'rest-client'
9
+
10
+ require "carterdte_smtp_filter/version"
11
+ require "carterdte_smtp_filter/config"
12
+ require "carterdte_smtp_filter/smtp_server"
13
+ require "carterdte_smtp_filter/message"
14
+ require "carterdte_smtp_filter/dte"
15
+ require "carterdte_smtp_filter/api_client"
16
+
17
+ module CarterdteSmtpFilter
18
+
19
+ def self.logger
20
+ logger_dest = CarterdteSmtpFilter::Config::log_file.nil? ? "/dev/null" : CarterdteSmtpFilter::Config::log_file
21
+ @logger = Logger.new(logger_dest)
22
+ @logger.datetime_format = '%Y-%m-%d %H:%M:%S'
23
+ @logger.formatter = proc { |severity, datetime, progname, msg| "#{datetime}: [#{severity}] #{msg.chomp}\n" }
24
+ @logger
25
+ end
26
+
27
+ end
@@ -0,0 +1,46 @@
1
+ module CarterdteSmtpFilter
2
+
3
+ module ApiClient
4
+ require 'rest-client'
5
+
6
+ def self.logger
7
+ CarterdteSmtpFilter.logger
8
+ end
9
+
10
+ def self.push(message)
11
+ post({payload: message})
12
+ end
13
+
14
+ def self.api_user
15
+ CarterdteSmtpFilter::Config::api_user
16
+ end
17
+
18
+ def self.api_host
19
+ CarterdteSmtpFilter::Config::api_host
20
+ end
21
+
22
+ def self.api_password
23
+ CarterdteSmtpFilter::Config::api_password
24
+ end
25
+
26
+ def self.post(opts = {})
27
+ url = opts[:url] || "https://#{CarterdteSmtpFilter::Config::api_host}/dtes"
28
+ payload = opts[:payload] || {}
29
+ begin
30
+ # We make sure we are sending JSON
31
+ JSON.parse payload
32
+ logger.info("Post #{payload} to #{url}")
33
+ resource = RestClient::Resource.new url, api_user, api_password
34
+ return if CarterdteSmtpFilter::Config::testing
35
+ response = resource.post payload, :content_type => :json, :accept => :json, :verify_ssl => OpenSSL::SSL::VERIFY_NONE
36
+ logger.info("Api response #{response}")
37
+ rescue Exception => e
38
+ logger.error("#{e} - #{url}")
39
+ response = false
40
+ end
41
+ response
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,19 @@
1
+ module CarterdteSmtpFilter
2
+
3
+ module Config
4
+ attr_accessor :config
5
+ OPTIONS = %w(bind_address bind_port return_host return_port elasticsearch_host elasticsearch_port max_connections debug api_user api_password api_host log_file stand_alone testing)
6
+
7
+ def self.parse(file = nil)
8
+ @config = YAML.load_file(file)
9
+ end
10
+
11
+ OPTIONS.each do |op|
12
+ self.class.instance_eval do
13
+ define_method(op) {@config[op].nil? ? false : @config[op].to_s}
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,90 @@
1
+ module CarterdteSmtpFilter
2
+
3
+ class Dte
4
+
5
+ VALID_NODES = %w(SetDTE Resultado)
6
+ attr_accessor :dte_hash
7
+
8
+ def initialize(xml_string)
9
+ @dte_hash = XmlSimple.xml_in xml_string
10
+ return false unless valid?
11
+ end
12
+
13
+ def valid?
14
+ (dte_hash.keys & VALID_NODES).any?
15
+ end
16
+
17
+ def envio?
18
+ msg_type == "envio"
19
+ end
20
+
21
+ def respuesta?
22
+ msg_type == "respuesta"
23
+ end
24
+
25
+ def to_json
26
+ return JSON.generate({}) unless valid?
27
+ JSON.generate({
28
+ rut_receptor: rut_receptor,
29
+ rut_emisor: rut_emisor,
30
+ msg_type: msg_type,
31
+ setdte_id: setdte_id,
32
+ dte_type: dte_type,
33
+ fecha_emision: fecha_emision,
34
+ fecha_recepcion: fecha_recepcion
35
+ })
36
+ end
37
+
38
+ def root_name
39
+ (dte_hash.keys & VALID_NODES).first
40
+ end
41
+
42
+ def root_node
43
+ @dte_hash[root_name].first
44
+ end
45
+
46
+ def get_data(data)
47
+ result = root_node["Caratula"].first[data].first if envio?
48
+ result = root_node["RecepcionEnvio"].first[data].first if respuesta?
49
+ return result.first if result.is_a? Array
50
+ result
51
+ end
52
+
53
+ def msg_type
54
+ return "respuesta" if root_name == "Resultado"
55
+ return "envio" if root_name == "SetDTE"
56
+ end
57
+
58
+ def setdte_id
59
+ return root_node["ID"] if envio?
60
+ get_data "EnvioDTEID"
61
+ end
62
+
63
+ def rut_emisor
64
+ get_data "RutEmisor"
65
+ end
66
+
67
+ def rut_receptor
68
+ get_data "RutReceptor"
69
+ end
70
+
71
+ def dte_type
72
+ return root_node["Caratula"].first["SubTotDTE"].first["TpoDTE"].first if envio?
73
+ return root_node["RecepcionEnvio"].first["RecepcionDTE"].first["TipoDTE"].first if respuesta?
74
+ end
75
+
76
+ def fecha_emision
77
+ time_stamp = get_data "TmstFirmaEnv" if envio?
78
+ time_stamp = root_node["Caratula"].first["TmstFirmaResp"].first if respuesta?
79
+ Time.parse(time_stamp).to_date
80
+ end
81
+
82
+ def fecha_recepcion
83
+ return nil if envio?
84
+ time_stamp = get_data "FchRecep"
85
+ Time.parse(time_stamp).to_date
86
+ end
87
+
88
+ end
89
+
90
+ end
@@ -0,0 +1,65 @@
1
+ module CarterdteSmtpFilter
2
+
3
+ class Message
4
+
5
+ attr_accessor :raw_data, :qid, :email, :response, :dte
6
+
7
+ def initialize(raw_data)
8
+ set_mail_defaults
9
+ @raw_data = raw_data
10
+ @email = Mail.read_from_string raw_data
11
+ @dte = extract_dte
12
+ @logger = CarterdteSmtpFilter.logger
13
+ @qid = nil
14
+ end
15
+
16
+ def extract_dte
17
+ return false unless @email.attachments.any?
18
+ file = @email.attachments.select {|m| m.sub_type == "xml"}.first
19
+ return false unless file
20
+ CarterdteSmtpFilter::Dte.new file.body.decoded
21
+ end
22
+
23
+ def process
24
+ return_email
25
+ return unless has_dte?
26
+ extract_qid_from_response
27
+ end
28
+
29
+ def has_dte?
30
+ @dte ? true : false
31
+ end
32
+
33
+ def to_json
34
+ JSON.generate({
35
+ to: @email.to,
36
+ from: @email.from,
37
+ cc: @email.cc,
38
+ date: @email.date.to_s,
39
+ qid: qid,
40
+ dte: JSON.parse(@dte.to_json)
41
+ })
42
+ end
43
+
44
+ def set_mail_defaults
45
+ Mail.defaults do
46
+ delivery_method :smtp, address: CarterdteSmtpFilter::Config::return_host, port: CarterdteSmtpFilter::Config::return_port,
47
+ return_response: true, enable_starttls_auto: false
48
+ end
49
+ end
50
+
51
+ def extract_qid_from_response
52
+ return false unless response.status == "250"
53
+ # We suppose the string is like "250 2.0.0 Ok: queued as J5D0AWOR4F8\n"
54
+ return false unless /Ok: queued as/.match response.string
55
+ @qid = response.string.split(/\s+/).last
56
+ end
57
+
58
+ def return_email
59
+ @logger.info("Returning email <#{email.message_id}> to #{CarterdteSmtpFilter::Config::return_host}:#{CarterdteSmtpFilter::Config::return_port}")
60
+ @response = email.deliver!
61
+ end
62
+
63
+ end
64
+
65
+ end