carterdte_smtp_filter 0.0.3

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
+ 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