diff --git a/.codespellrc b/.codespellrc new file mode 100644 index 000000000..34c28be63 --- /dev/null +++ b/.codespellrc @@ -0,0 +1,7 @@ +[codespell] +# Ref: https://github.com/codespell-project/codespell#using-a-config-file +skip = .git,.gitignore,.gitattributes,*.svg,vendor,*.lock,.codespellrc,CHANGELOG.md,*/dkim_signing/*,*/postfix-bounce.msg,*/signing.key +check-hidden = true +# ignore-regex = +# checkin - method name in connection_pool.rb (not "checking"/"check in") +ignore-words-list = checkin diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 0b37cd054..8aa75f4bd 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -35,4 +35,4 @@ If applicable, add screenshots to help explain your problem. ## Additional information/context -Add any other context about the problem here. It is particularily useful to include log extracts (after removing private information). +Add any other context about the problem here. It is particularly useful to include log extracts (after removing private information). diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml new file mode 100644 index 000000000..6e996fdec --- /dev/null +++ b/.github/workflows/codespell.yml @@ -0,0 +1,23 @@ +# Codespell configuration is within .codespellrc +--- +name: Codespell + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + +jobs: + codespell: + name: Check for spelling errors + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Codespell + uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 # v2.2 diff --git a/.gitignore b/.gitignore index b89b11b4f..96a88d934 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,6 @@ BRANCH .rubocop-https* .env* +node_modules +yarn.lock + diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 931d27504..84d468fa7 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.3.4" + ".": "3.3.6" } diff --git a/.rubocop.yml b/.rubocop.yml index 59d78f88d..c0a52e4fa 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -51,7 +51,7 @@ Layout/EmptyLinesAroundModuleBody: # Space is required following -> when writing a lambda: # -# somethign = -> (var) { block } +# something = -> (var) { block } Layout/SpaceInLambdaLiteral: EnforcedStyle: require_space @@ -115,7 +115,7 @@ Lint/BooleanSymbol: Style/SymbolProc: Enabled: false -# Allow a maxmium of 5 arguments and don't include keyword arguments +# Allow a maximum of 5 arguments and don't include keyword arguments Metrics/ParameterLists: Max: 5 CountKeywordArgs: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b78a9257..9bc3ae25b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,52 @@ This file contains all the latest changes and updates to Postal. +## [3.3.6](https://github.com/postalserver/postal/compare/3.3.5...3.3.6) (2026-04-28) + + +### Bug Fixes + +* **messages:** sandbox rendered email HTML as extra XSS defence ([cad2aa6](https://github.com/postalserver/postal/commit/cad2aa6808519a3ff25215f09f4966d9fa3bb372)) + + +### Miscellaneous Chores + +* ignore node modules and yarn.lock ([b611d57](https://github.com/postalserver/postal/commit/b611d577af79b8e1e75b6d47fa04d1ba03e34eec)) + + +### Code Refactoring + +* **auth:** tighten return_to validation ([84f4e20](https://github.com/postalserver/postal/commit/84f4e20f05db2d11b0144f95960c956f8221e657)) +* **helpers:** escape interpolated values in select options ([9243524](https://github.com/postalserver/postal/commit/924352403553dcfcc569876ca76c219493fac9d6)) +* **tracking:** remove unused src image proxy ([dca7f90](https://github.com/postalserver/postal/commit/dca7f90b9046247c0d953567be35921167e79d87)) + +## [3.3.5](https://github.com/postalserver/postal/compare/3.3.4...3.3.5) (2026-02-01) + + +### Bug Fixes + +* **deliveries:** escape delivery details to prevent HTML injection ([11419f9](https://github.com/postalserver/postal/commit/11419f99140e13688a9613cab3ee03f8d3cbae45)) +* **health_server:** use rackup handler instead of rack handler ([7c47422](https://github.com/postalserver/postal/commit/7c47422c865e738c4d6af0fed1cca4405288341f)) +* oidc scopes are invalid when concatenated ([#3332](https://github.com/postalserver/postal/issues/3332)) ([9c5f96a](https://github.com/postalserver/postal/commit/9c5f96ae90cf06dcd5db776806865752f667bd95)) +* typo in process logging ([#3212](https://github.com/postalserver/postal/issues/3212)) ([b7e5232](https://github.com/postalserver/postal/commit/b7e5232e077b3c9b7a999dcb6676fba0ec61458e)) +* typo in the credentials page ([fd3c7cc](https://github.com/postalserver/postal/commit/fd3c7ccdf6dc4ee0a76c9523cbd735159e4b8000)) +* update url for v2 config ([#3225](https://github.com/postalserver/postal/issues/3225)) ([e00098b](https://github.com/postalserver/postal/commit/e00098b8003cf37f2708f536871b3ade377aed2d)) + + +### Documentation + +* **process.rb:** add help about time unit used by metric ([#3339](https://github.com/postalserver/postal/issues/3339)) ([f5325c4](https://github.com/postalserver/postal/commit/f5325c49ff1152ad53eaaec98717ad3412d379ae)) + + +### Miscellaneous Chores + +* **deps:** upgrade puma, net-imap and other deps ([c03c44b](https://github.com/postalserver/postal/commit/c03c44b442a29aa9881c1e1aae60bead9776a6b6)) +* **dockerfile:** reduce container size ([86de372](https://github.com/postalserver/postal/commit/86de372382bd62bdd5d1372254f8817b0360bd56)) +* remove version from docker-compose.yml ([c78000c](https://github.com/postalserver/postal/commit/c78000ca8f2998aa04648f465060768db6467de6)) +* upgrade resolv to 0.6.2 ([d00d978](https://github.com/postalserver/postal/commit/d00d978872a96369544303d08f6a9d11cdf56b62)) +* upgrade to rails 7.1 and ruby 3.4 ([#3457](https://github.com/postalserver/postal/issues/3457)) ([ab6d443](https://github.com/postalserver/postal/commit/ab6d4430baa33a05f1aa66e776cc2a5bcaa0ede8)) +* upgrade uri gem to 1.0.3 ([f193b8e](https://github.com/postalserver/postal/commit/f193b8e77fc096382ab7aaa6a2c29641b4cb12df)) + ## [3.3.4](https://github.com/postalserver/postal/compare/3.3.3...3.3.4) (2024-06-20) @@ -287,7 +333,7 @@ This version of Postal introduces a number of larger changes. Please be sure to * **rubocop:** Lint/UselessAssignment ([7590a46](https://github.com/postalserver/postal/commit/7590a462341bddd412e660db9546ba1909aea9d7)) * **rubocop:** Naming/FileName ([919a601](https://github.com/postalserver/postal/commit/919a60116c5d81ed787061ff4614da4f1e067d4e)) * **rubocop:** Naming/MemoizedInstanceVariableName ([9563f30](https://github.com/postalserver/postal/commit/9563f30c96fba12073e845319b8d79a542d88109)) -* **rubocop:** relax method length and block nexting for now ([b0ac9ef](https://github.com/postalserver/postal/commit/b0ac9ef0b96ab78c2961f45b6e9f20f87a6f1d07)) +* **rubocop:** relax method length and block nesting for now ([b0ac9ef](https://github.com/postalserver/postal/commit/b0ac9ef0b96ab78c2961f45b6e9f20f87a6f1d07)) * **rubocop:** remaining offences ([ec63666](https://github.com/postalserver/postal/commit/ec636661d5c4b9e8f48e6f263ffef834acb68b39)) * **rubocop:** Security/YAMLLoad ([389ea77](https://github.com/postalserver/postal/commit/389ea7705047bf8700836137514b2497af3c6c01)) * **rubocop:** Style/AndOr ([b9f3f31](https://github.com/postalserver/postal/commit/b9f3f313f8ec992917bad3a51f0481f89675e935)) @@ -423,7 +469,7 @@ This version of Postal introduces a number of larger changes. Please be sure to - Fix to newline conversion process ([9f4ef8](https://github.com/postalserver/postal/commit/9f4ef8f57a839c5529b4f00a36b832740386b4ed)) - Remove custom scrollbars ([b22f1b](https://github.com/postalserver/postal/commit/b22f1bdb2e2d66b096ca993d6a5f4f708274a4a2)) - Truncate 'output' field to avoid overflowing varchar(512) in database ([a188a1](https://github.com/postalserver/postal/commit/a188a161cbdcfd70158b09b53cef622842357c26)) -- Fix link replacement in multipart messsages ([7ea00d](https://github.com/postalserver/postal/commit/7ea00dfa3bc3c7650cc2b134beacbff22101a913)) +- Fix link replacement in multipart messages ([7ea00d](https://github.com/postalserver/postal/commit/7ea00dfa3bc3c7650cc2b134beacbff22101a913)) - Fix confusing error message when deleting IP pools ([cefc7d](https://github.com/postalserver/postal/commit/cefc7d17b82f610001859a8e323ee1dfde149ba5)) - Connect to correct IP rather than hostname suring SMTP delivery ([159509](https://github.com/postalserver/postal/commit/159509a3ed29ae33cba522b255904992922dcfdf)) - Change retry timings to avoid re-sending messages too early ([c8d27b](https://github.com/postalserver/postal/commit/c8d27b2963af122d6555abdf0742d2d2d6f11ce5)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c6befd23b..3acca65df 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,7 +34,7 @@ openssl genrsa -out config/postal/signing.key 2048 If you're running the tests (and you probably should be), you'll find an example file for test configuration in `config/examples/test.yml`. This should be placed in `config/postal/postal.test.yml` with the appropriate values. -If you prefer, you can configure Postal using environment variables. These should be placed in `.env` or `.env.test` as apprpriate. +If you prefer, you can configure Postal using environment variables. These should be placed in `.env` or `.env.test` as appropriate. ## Running diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d2c36cda5..24498f7ed 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -62,10 +62,13 @@ def append_info_to_payload(payload) end def url_with_return_to(url) - if params[:return_to].blank? || !params[:return_to].starts_with?("/") + return_to = params[:return_to] + if return_to.blank? || + !return_to.start_with?("/") || + return_to.start_with?("//", "/\\") url_for(url) else - params[:return_to] + return_to end end diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb index ea0e940ce..9d59f08e4 100644 --- a/app/controllers/messages_controller.rb +++ b/app/controllers/messages_controller.rb @@ -89,6 +89,18 @@ def deliveries end def html_raw + override_content_security_policy_directives( + default_src: %w('none'), + script_src: %w('none'), + style_src: %w('unsafe-inline'), + img_src: %w(* data:), + font_src: %w(*), + frame_ancestors: %w('self'), + form_action: %w('none'), + base_uri: %w('none') + ) + response.headers["X-Content-Type-Options"] = "nosniff" + response.headers["Referrer-Policy"] = "no-referrer" render html: @message.html_body_without_tracking_image.html_safe end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c6acf4563..17d124217 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -3,6 +3,7 @@ module ApplicationHelper def format_delivery_details(server, text) + text = h(text) text.gsub!(//) do id = ::Regexp.last_match(1).to_i link_to("message ##{id}", organization_server_message_path(server.organization, server, id), class: "u-link") @@ -32,7 +33,7 @@ def domain_options_for_select(server, selected_domain = nil, options = {}) s << "" server_domains.each do |domain| selected = domain == selected_domain ? "selected='selected'" : "" - s << "" + s << "" end s << "" end @@ -42,7 +43,7 @@ def domain_options_for_select(server, selected_domain = nil, options = {}) s << "" organization_domains.each do |domain| selected = domain == selected_domain ? "selected='selected'" : "" - s << "" + s << "" end s << "" end @@ -59,7 +60,7 @@ def endpoint_options_for_select(server, selected_value = nil, options = {}) http_endpoints.each do |endpoint| value = "#{endpoint.class}##{endpoint.uuid}" selected = value == selected_value ? "selected='selected'" : "" - s << "" + s << "" end s << "" end @@ -70,7 +71,7 @@ def endpoint_options_for_select(server, selected_value = nil, options = {}) smtp_endpoints.each do |endpoint| value = "#{endpoint.class}##{endpoint.uuid}" selected = value == selected_value ? "selected='selected'" : "" - s << "" + s << "" end s << "" end @@ -81,7 +82,7 @@ def endpoint_options_for_select(server, selected_value = nil, options = {}) address_endpoints.each do |endpoint| value = "#{endpoint.class}##{endpoint.uuid}" selected = value == selected_value ? "selected='selected'" : "" - s << "" + s << "" end s << "" end @@ -93,7 +94,7 @@ def endpoint_options_for_select(server, selected_value = nil, options = {}) selected = (selected_value == mode ? "selected='selected'" : "") text = t("route_modes.#{mode.underscore}") - s << "" + s << "" end s << "" end diff --git a/app/lib/message_dequeuer/incoming_message_processor.rb b/app/lib/message_dequeuer/incoming_message_processor.rb index 6f69dbceb..51451b894 100644 --- a/app/lib/message_dequeuer/incoming_message_processor.rb +++ b/app/lib/message_dequeuer/incoming_message_processor.rb @@ -82,7 +82,7 @@ def inspect_message def fail_if_spam return if queued_message.message.spam_score < queued_message.server.spam_failure_threshold - log "message has a spam score higher than the server's maxmimum, hard failing", server_threshold: queued_message.server.spam_failure_threshold + log "message has a spam score higher than the server's maximum, hard failing", server_threshold: queued_message.server.spam_failure_threshold create_delivery "HardFail", details: "Message's spam score is higher than the failure threshold for this server. " \ "Threshold is currently #{queued_message.server.spam_failure_threshold}." diff --git a/app/lib/smtp_client/endpoint.rb b/app/lib/smtp_client/endpoint.rb index 5449e695a..66a988bc7 100644 --- a/app/lib/smtp_client/endpoint.rb +++ b/app/lib/smtp_client/endpoint.rb @@ -88,7 +88,7 @@ def start_smtp_session(source_ip_address: nil, allow_ssl: true) end # Send a message to the current SMTP session (or create one if there isn't one for this endpoint). - # If sending messsage encouters some connection errors, retry again after re-establishing the SMTP + # If sending message encounters some connection errors, retry again after re-establishing the SMTP # session. # # @param raw_message [String] the raw message to send diff --git a/app/lib/smtp_server/client.rb b/app/lib/smtp_server/client.rb index 2a70667c9..efa78e307 100644 --- a/app/lib/smtp_server/client.rb +++ b/app/lib/smtp_server/client.rb @@ -517,7 +517,7 @@ def finished msg.bounce = 1 end else - # There's no return path route, we just need to insert the mesage + # There's no return path route, we just need to insert the message # without going through the route. message = server.message_db.new_message message.rcpt_to = rcpt_to diff --git a/app/lib/smtp_server/server.rb b/app/lib/smtp_server/server.rb index 90902b5a8..4cdfba50e 100644 --- a/app/lib/smtp_server/server.rb +++ b/app/lib/smtp_server/server.rb @@ -308,7 +308,7 @@ def register_prometheus_metrics labels: [:type, :error] register_prometheus_counter :postal_smtp_server_tls_connections_total, - docstring: "The number of successfuly TLS connections established" + docstring: "The number of successfully TLS connections established" Client.register_prometheus_metrics end diff --git a/app/models/bounce_message.rb b/app/models/bounce_message.rb index 03200720d..c5f2e0230 100644 --- a/app/models/bounce_message.rb +++ b/app/models/bounce_message.rb @@ -46,7 +46,7 @@ def body For further assistance please contact #{postmaster_address}. Please include the details below to help us identify the issue. Message Token: #{@message.token}@#{@server.token} - Orginal Message ID: #{@message.message_id} + Original Message ID: #{@message.message_id} Mail from: #{@message.mail_from} Rcpt To: #{@message.rcpt_to} BODY diff --git a/app/senders/smtp_sender.rb b/app/senders/smtp_sender.rb index 1f3c863fd..a1af5ac6f 100644 --- a/app/senders/smtp_sender.rb +++ b/app/senders/smtp_sender.rb @@ -4,7 +4,7 @@ class SMTPSender < BaseSender attr_reader :endpoints - # @param domain [String] the domain to send mesages to + # @param domain [String] the domain to send messages to # @param source_ip_address [IPAddress] the IP address to send messages from # @param log_id [String] an ID to use when logging requests def initialize(domain, source_ip_address = nil, servers: nil, log_id: nil, rcpt_to: nil) @@ -15,7 +15,7 @@ def initialize(domain, source_ip_address = nil, servers: nil, log_id: nil, rcpt_ # An array of servers to forcefully send the message to @servers = servers - # Stores all connection errors which we have seen during this send sesssion. + # Stores all connection errors which we have seen during this send session. @connection_errors = [] # Stores all endpoints that we have attempted to deliver mail to @endpoints = [] @@ -57,7 +57,7 @@ def send_message(message) mail_from = determine_mail_from_for_message(message) raw_message = message.raw_message - # Append the Resent-Sender header to the mesage to include the + # Append the Resent-Sender header to the message to include the # MAIL FROM if the installation is configured to use that? if Postal::Config.postal.use_resent_sender_header? raw_message = "Resent-Sender: #{mail_from}\r\n" + raw_message @@ -168,7 +168,7 @@ def resolve_mx_records_for_domain hostnames.map { |hostname| SMTPClient::Server.new(hostname) } end - # Attempt to begin an SMTP sesssion for the given endpoint. If successful, this endpoint + # Attempt to begin an SMTP session for the given endpoint. If successful, this endpoint # becomes the current endpoints for the SMTP sender. # # Returns true if the session was established. diff --git a/app/views/domains/new.html.haml b/app/views/domains/new.html.haml index 474a2b0ca..95cb38658 100644 --- a/app/views/domains/new.html.haml +++ b/app/views/domains/new.html.haml @@ -29,7 +29,7 @@ = f.select :verification_method, Domain::VERIFICATION_METHODS, {}, :class => 'input input--select' .fieldSet__text Choose how you'd like to verify your ownership of this domain. If you choose E-Mail we can send you - an email with a code whcih you'll need to enter - you can choose from a set of pre-defined addresses for + an email with a code which you'll need to enter - you can choose from a set of pre-defined addresses for the domain. Using DNS you'll need to add a TXT record on this domain using your DNS provider. .fieldSetSubmit diff --git a/app/views/messages/html.html.haml b/app/views/messages/html.html.haml index 357f2cb50..826f7e176 100644 --- a/app/views/messages/html.html.haml +++ b/app/views/messages/html.html.haml @@ -14,4 +14,4 @@ This means that we no longer store the raw data for this e-mail or the e-mail didn't include a HTML part. - else - %iframe{:width => "100%", :height => "100%", :src => html_raw_organization_server_message_path(organization, @server, @message.id)} + %iframe{:width => "100%", :height => "100%", :sandbox => "allow-popups allow-popups-to-escape-sandbox", :referrerpolicy => "no-referrer", :src => html_raw_organization_server_message_path(organization, @server, @message.id)} diff --git a/app/views/messages/spam_checks.html.haml b/app/views/messages/spam_checks.html.haml index 95483b6b9..50431daec 100644 --- a/app/views/messages/spam_checks.html.haml +++ b/app/views/messages/spam_checks.html.haml @@ -12,7 +12,7 @@ .noData.noData--clean %h2.noData__title This message doesn't have any spam checks. %p.noData__text - This likely means we haven't scanned this message to determine its likelyhood + This likely means we haven't scanned this message to determine its likelihood of being spam. It may take a few seconds to appear after a new message is received. diff --git a/doc/config/configuration.md b/doc/config/configuration.md index aa9a71159..0a175a4f1 100644 --- a/doc/config/configuration.md +++ b/doc/config/configuration.md @@ -16,7 +16,7 @@ By default, tests will use the `config/postal/postal.test.yml` configuration fil ## Containers -Within a container, Postal will for a config file in `/config/postal.yml` unless overriden by the `POSTAL_CONFIG_FILE_PATH` environment variable. +Within a container, Postal will for a config file in `/config/postal.yml` unless overridden by the `POSTAL_CONFIG_FILE_PATH` environment variable. ## Ports & Bind Addresses diff --git a/doc/config/environment-variables.md b/doc/config/environment-variables.md index 940424e04..37274837c 100644 --- a/doc/config/environment-variables.md +++ b/doc/config/environment-variables.md @@ -20,8 +20,8 @@ This document contains all the environment variables which are available for thi | `POSTAL_TRUSTED_PROXIES` | Array of strings | An array of IP addresses to trust for proxying requests to Postal (in addition to localhost addresses) | [] | | `POSTAL_QUEUED_MESSAGE_LOCK_STALE_DAYS` | Integer | The number of days after which to consider a lock as stale. Messages with stale locks will be removed and not retried. | 1 | | `POSTAL_BATCH_QUEUED_MESSAGES` | Boolean | When enabled queued messages will be de-queued in batches based on their destination | true | -| `WEB_SERVER_DEFAULT_PORT` | Integer | The default port the web server should listen on unless overriden by the PORT environment variable | 5000 | -| `WEB_SERVER_DEFAULT_BIND_ADDRESS` | String | The default bind address the web server should listen on unless overriden by the BIND_ADDRESS environment variable | 127.0.0.1 | +| `WEB_SERVER_DEFAULT_PORT` | Integer | The default port the web server should listen on unless overridden by the PORT environment variable | 5000 | +| `WEB_SERVER_DEFAULT_BIND_ADDRESS` | String | The default bind address the web server should listen on unless overridden by the BIND_ADDRESS environment variable | 127.0.0.1 | | `WEB_SERVER_MAX_THREADS` | Integer | The maximum number of threads which can be used by the web server | 5 | | `WORKER_DEFAULT_HEALTH_SERVER_PORT` | Integer | The default port for the worker health server to listen on | 9090 | | `WORKER_DEFAULT_HEALTH_SERVER_BIND_ADDRESS` | String | The default bind address for the worker health server to listen on | 127.0.0.1 | @@ -46,8 +46,8 @@ This document contains all the environment variables which are available for thi | `GELF_HOST` | String | GELF-capable host to send logs to | | | `GELF_PORT` | Integer | GELF port to send logs to | 12201 | | `GELF_FACILITY` | String | The facility name to add to all log entries sent to GELF | postal | -| `SMTP_SERVER_DEFAULT_PORT` | Integer | The default port the SMTP server should listen on unless overriden by the PORT environment variable | 25 | -| `SMTP_SERVER_DEFAULT_BIND_ADDRESS` | String | The default bind address the SMTP server should listen on unless overriden by the BIND_ADDRESS environment variable | :: | +| `SMTP_SERVER_DEFAULT_PORT` | Integer | The default port the SMTP server should listen on unless overridden by the PORT environment variable | 25 | +| `SMTP_SERVER_DEFAULT_BIND_ADDRESS` | String | The default bind address the SMTP server should listen on unless overridden by the BIND_ADDRESS environment variable | :: | | `SMTP_SERVER_DEFAULT_HEALTH_SERVER_PORT` | Integer | The default port for the SMTP server health server to listen on | 9091 | | `SMTP_SERVER_DEFAULT_HEALTH_SERVER_BIND_ADDRESS` | String | The default bind address for the SMTP server health server to listen on | 127.0.0.1 | | `SMTP_SERVER_TLS_ENABLED` | Boolean | Enable TLS for the SMTP server (requires certificate) | false | diff --git a/doc/config/yaml.yml b/doc/config/yaml.yml index f3a735a9f..76997349c 100644 --- a/doc/config/yaml.yml +++ b/doc/config/yaml.yml @@ -35,9 +35,9 @@ postal: batch_queued_messages: true web_server: - # The default port the web server should listen on unless overriden by the PORT environment variable + # The default port the web server should listen on unless overridden by the PORT environment variable default_port: 5000 - # The default bind address the web server should listen on unless overriden by the BIND_ADDRESS environment variable + # The default bind address the web server should listen on unless overridden by the BIND_ADDRESS environment variable default_bind_address: 127.0.0.1 # The maximum number of threads which can be used by the web server max_threads: 5 @@ -99,9 +99,9 @@ gelf: facility: postal smtp_server: - # The default port the SMTP server should listen on unless overriden by the PORT environment variable + # The default port the SMTP server should listen on unless overridden by the PORT environment variable default_port: 25 - # The default bind address the SMTP server should listen on unless overriden by the BIND_ADDRESS environment variable + # The default bind address the SMTP server should listen on unless overridden by the BIND_ADDRESS environment variable default_bind_address: :: # The default port for the SMTP server health server to listen on default_health_server_port: 9091 diff --git a/lib/postal/config_schema.rb b/lib/postal/config_schema.rb index e3c6415d5..cd57cb78a 100644 --- a/lib/postal/config_schema.rb +++ b/lib/postal/config_schema.rb @@ -105,12 +105,12 @@ module Postal group :web_server do integer :default_port do - description "The default port the web server should listen on unless overriden by the PORT environment variable" + description "The default port the web server should listen on unless overridden by the PORT environment variable" default 5000 end string :default_bind_address do - description "The default bind address the web server should listen on unless overriden by the BIND_ADDRESS environment variable" + description "The default bind address the web server should listen on unless overridden by the BIND_ADDRESS environment variable" default "127.0.0.1" end @@ -243,12 +243,12 @@ module Postal group :smtp_server do integer :default_port do - description "The default port the SMTP server should listen on unless overriden by the PORT environment variable" + description "The default port the SMTP server should listen on unless overridden by the PORT environment variable" default 25 end string :default_bind_address do - description "The default bind address the SMTP server should listen on unless overriden by the BIND_ADDRESS environment variable" + description "The default bind address the SMTP server should listen on unless overridden by the BIND_ADDRESS environment variable" default "::" end diff --git a/lib/postal/message_db/message.rb b/lib/postal/message_db/message.rb index 3a2c7a690..dc7cb25a3 100644 --- a/lib/postal/message_db/message.rb +++ b/lib/postal/message_db/message.rb @@ -508,7 +508,7 @@ def original_messages end # - # Was thsi message sent to a return path? + # Was this message sent to a return path? # def rcpt_to_return_path? !!(rcpt_to =~ /@#{Regexp.escape(Postal::Config.dns.custom_return_path_prefix)}\./) @@ -552,7 +552,7 @@ def cancel_hold def parse_content parse_result = Postal::MessageParser.new(self) if parse_result.actioned? - # Somethign was changed, update the raw message + # Something was changed, update the raw message @database.update(raw_table, { data: parse_result.new_body }, where: { id: raw_body_id }) @database.update(raw_table, { data: parse_result.new_headers }, where: { id: raw_headers_id }) @raw = parse_result.new_body diff --git a/lib/tracking_middleware.rb b/lib/tracking_middleware.rb index bee3a6378..cddffb638 100644 --- a/lib/tracking_middleware.rb +++ b/lib/tracking_middleware.rb @@ -43,30 +43,16 @@ def dispatch_image_request(request, server_token, message_token) rescue Postal::MessageDB::Message::NotFound # This message has been removed, we'll just continue to serve the image rescue StandardError => e - # Somethign else went wrong. We don't want to stop the image loading though because + # Something else went wrong. We don't want to stop the image loading though because # this is our problem. Log this exception though. Sentry.capture_exception(e) if defined?(Sentry) end - source_image = request.params["src"] - case source_image - when nil + if request.params["src"].nil? headers = {} headers["Content-Type"] = "image/png" headers["Content-Length"] = TRACKING_PIXEL.bytesize.to_s [200, headers, [TRACKING_PIXEL]] - when /\Ahttps?:\/\// - response = Postal::HTTP.get(source_image, timeout: 3) - return [404, {}, ["Not found"]] unless response[:code] == 200 - - headers = {} - headers["Content-Type"] = response[:headers]["content-type"]&.first - headers["Last-Modified"] = response[:headers]["last-modified"]&.first - headers["Cache-Control"] = response[:headers]["cache-control"]&.first - headers["Etag"] = response[:headers]["etag"]&.first - headers["Content-Length"] = response[:body].bytesize.to_s - [200, headers, [response[:body]]] - else [400, {}, ["Invalid/missing source image"]] end diff --git a/spec/examples/full_legacy_config_file.yml b/spec/examples/full_legacy_config_file.yml index c078fc075..9b17dea6e 100644 --- a/spec/examples/full_legacy_config_file.yml +++ b/spec/examples/full_legacy_config_file.yml @@ -2,7 +2,7 @@ # less than v3. It remains supported in v3+ by mapping these values to their # correct values. Support for this file format will be removed in Postal v4. # -# It exists here for reference but also to faciliate testing to ensure the +# It exists here for reference but also to facilitate testing to ensure the # legacy mapping works as expected version: 1 diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb new file mode 100644 index 000000000..4beb3de98 --- /dev/null +++ b/spec/helpers/application_helper_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe ApplicationHelper, type: :helper do + describe "#endpoint_options_for_select" do + let(:server) { create(:server) } + + context "when an endpoint has HTML characters in its description" do + let(:payload) { %q(x'">) } + + before do + create(:http_endpoint, server: server, name: payload) + end + + it "HTML-escapes the endpoint description in the option text" do + html = helper.endpoint_options_for_select(server) + + # The raw payload must not appear verbatim — if it does, the browser + # will execute the ") + + # Escaped form should appear instead. + expect(html).to include("<script>alert(1)</script>") + end + + it "does not allow the payload to break out of the option tag" do + html = helper.endpoint_options_for_select(server) + + # The ' and > characters in the payload must be escaped so they + # cannot close the opening