Method: As2::Client#send_file

Defined in:
lib/as2/client.rb

#send_file(file_name, content: nil, content_type: 'application/EDI-Consent') ⇒ As2::Client::Result

Send a file to a partner

* If the content parameter is omitted, then `file_name` must be a path
  to a local file, whose contents will be sent to the partner.
* If content parameter is specified, file_name is only used to tell the
  partner the original name of the file.

TODO: refactor to separate “build an outbound message” from “send an outbound message” main benefit would be allowing the test suite to be more straightforward. (wouldn’t need webmock just to verify what kind of message we built…)

Parameters:

  • file_name (String)
  • content (String) (defaults to: nil)
  • content_type (String) (defaults to: 'application/EDI-Consent')

    This is the MIME Content-Type describing the ‘content` param, and will be included in the SMIME payload. It is not the HTTP Content-Type.

Returns:



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/as2/client.rb', line 61

def send_file(file_name, content: nil, content_type: 'application/EDI-Consent')
  outbound_mic_algorithm = 'sha256'
  outbound_message_id = As2.generate_message_id(@server_info)

  req = Net::HTTP::Post.new @partner.url.path
  req['AS2-Version'] = '1.0' # 1.1 includes compression support, which we dont implement.
  req['AS2-From'] = As2.quoted_system_identifier(as2_from)
  req['AS2-To'] = As2.quoted_system_identifier(as2_to)
  req['Subject'] = 'AS2 Transaction'
  req['Content-Type'] = 'application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m'
  req['Date'] = Time.now.rfc2822
  req['Disposition-Notification-To'] = @server_info.url.to_s
  req['Disposition-Notification-Options'] = "signed-receipt-protocol=optional, pkcs7-signature; signed-receipt-micalg=optional, #{outbound_mic_algorithm}"
  req['Content-Disposition'] = 'attachment; filename="smime.p7m"'
  req['Recipient-Address'] = @partner.url.to_s
  req['Message-ID'] = outbound_message_id

  document_content = content || File.read(file_name)
  outbound_format = @partner&.outbound_format || 'v0'

  if outbound_format == 'v1'
    format_method = :format_body_v1
  else
    format_method = :format_body_v0
  end

  document_payload, request_body = send(format_method,
                                     document_content,
                                     content_type: content_type,
                                     file_name: file_name
                                   )

  encrypted = OpenSSL::PKCS7.encrypt(
                [@partner.encryption_certificate],
                request_body,
                @partner.encryption_cipher_instance
              )

  # > HTTP can handle binary data and so there is no need to use the
  # > content transfer encodings of MIME
  #
  # https://datatracker.ietf.org/doc/html/rfc4130#section-5.2.1
  req.body = encrypted.to_der

  resp = nil
  exception = nil
  mdn_report = {}

  begin
    # note: to pass this traffic through a debugging proxy (like Charles)
    # set ENV['http_proxy'].
    http = Net::HTTP.new(@partner.url.host, @partner.url.port)

    use_ssl = @partner.url.scheme == 'https'
    http.use_ssl = use_ssl
    if use_ssl
      if @partner.tls_verify_mode
        http.verify_mode = @partner.tls_verify_mode
      end
    end

    # http.set_debug_output $stderr

    http.start do
      resp = http.request(req)
    end

    if resp && resp.code.start_with?('2')
      mdn_report = evaluate_mdn(
                     mdn_content_type: resp['Content-Type'],
                     mdn_body: resp.body,
                     original_message_id: req['Message-ID'],
                     original_body: document_payload
                   )
    end
  rescue => e
    exception = e
  end

  Result.new(
    request: req,
    response: resp,
    mic_matched: mdn_report[:mic_matched],
    mid_matched: mdn_report[:mid_matched],
    body: mdn_report[:plain_text_body],
    disposition: mdn_report[:disposition],
    signature_verification_error: mdn_report[:signature_verification_error],
    exception: exception,
    outbound_message_id: outbound_message_id
  )
end