1
0
مراية لـ https://github.com/postalserver/postal.git تم المزامنة 2026-03-03 14:24:06 +00:00

Compare commits

64 الالتزامات
2.2.2 ... 2.3.0

المؤلف SHA1 الرسالة التاريخ
Adam Cooke
d7dce16c50 Merge pull request #2790 from postalserver/release-please--branches--main
chore(main): release 2.3.0
2024-02-14 15:04:09 +00:00
github-actions[bot]
b8bab1bd0e chore(main): release 2.3.0 2024-02-13 15:59:15 +00:00
Adam Cooke
7c23994d24 fix: use correct method for disconnecting smtp connections 2024-02-13 15:57:59 +00:00
Adam Cooke
42ab5b3a6b fix: explicitly disable TLS & starttls for unknown SSL modes
closes #2564
2024-02-13 15:57:48 +00:00
Adam Cooke
f9f7fb30fe fix: retry mysql connections on message DB pool 2024-02-13 15:56:40 +00:00
Adam Cooke
b8cb563553 Merge pull request #2801 from postalserver/smtp-tests
Tests for the SMTP Server
2024-02-13 15:55:57 +00:00
Adam Cooke
e83e2a5e33 Merge pull request #2799 from postalserver/remove-server-fd
Remove SMTP server reloading
2024-02-13 15:55:30 +00:00
Adam Cooke
c3c304e98b refactor: remove reloading on the smtp server 2024-02-13 15:51:44 +00:00
Adam Cooke
241f37e78d Merge pull request #2797 from postalserver/rubocop
Code Quality Improvements
2024-02-13 14:24:41 +00:00
Adam Cooke
c83601af69 chore: silence message DB migrations during provisioning 2024-02-13 11:56:48 +00:00
Adam Cooke
6214892710 chore: annotate models 2024-02-13 11:46:35 +00:00
Adam Cooke
1fceef7cea fix: add ruby platform to gemfile 2024-02-12 18:14:29 +00:00
Adam Cooke
dece1d487a test: add initial tests for Postal::SMTPServer::Client 2024-02-12 18:07:44 +00:00
Adam Cooke
ec636661d5 style(rubocop): remaining offences 2024-02-12 09:55:20 +00:00
Adam Cooke
c6326a6524 style(rubocop): Style/MultilineBlockChain 2024-02-12 09:55:19 +00:00
Adam Cooke
013b3ea931 style(rubocop): Style/PreferredHashMethods 2024-02-12 09:55:19 +00:00
Adam Cooke
ffcb707247 style(rubocop): Style/MissingRespondToMissing 2024-02-12 09:55:19 +00:00
Adam Cooke
83ac764510 style(rubocop): Style/HashExcept 2024-02-12 09:55:19 +00:00
Adam Cooke
c995027ff5 style(rubocop): Style/HashEachMethods 2024-02-12 09:55:19 +00:00
Adam Cooke
ec7dcf4f9a style(rubocop): Lint/UnderscorePrefixedVariableName 2024-02-12 09:55:19 +00:00
Adam Cooke
278ef0886a style(rubocop): Lint/SuppressedException 2024-02-12 09:55:18 +00:00
Adam Cooke
bab6346239 style(rubocop): Lint/DuplicateMethods 2024-02-12 09:55:18 +00:00
Adam Cooke
a1dc0f77ac style(rubocop): Lint/DuplicateBranch 2024-02-12 09:55:18 +00:00
Adam Cooke
0e0aca06c9 style(rubocop): Layout/* 2024-02-12 09:55:18 +00:00
Adam Cooke
9ce28a427f style(rubocop): Style/SelectByRegexp 2024-02-12 09:55:18 +00:00
Adam Cooke
157d11457c style(rubocop): Style/GlobalVars 2024-02-12 09:55:18 +00:00
Adam Cooke
e896f4689a style(rubocop): Style/ClassAndModuleChildren 2024-02-12 09:55:18 +00:00
Adam Cooke
b9f3f313f8 style(rubocop): Style/AndOr 2024-02-12 09:55:17 +00:00
Adam Cooke
4674e63b5f style(rubocop): Lint/MissingSuper 2024-02-12 09:55:15 +00:00
Adam Cooke
be97f43308 style(rubocop): disable Style/SpecialGlobalVars 2024-02-12 09:40:35 +00:00
Adam Cooke
75be690748 style(rubocop): Style/GlobalStdStream 2024-02-12 09:40:35 +00:00
Adam Cooke
9563f30c96 style(rubocop): Naming/MemoizedInstanceVariableName 2024-02-12 09:40:34 +00:00
Adam Cooke
00a02f2655 style(rubocop): Style/SafeNavigation 2024-02-12 09:40:34 +00:00
Adam Cooke
04a34831c7 style(rubocop): Style/For 2024-02-12 09:40:34 +00:00
Adam Cooke
6a58ecf605 style(rubocop): Style/IdenticalConditionalBranches 2024-02-12 09:40:31 +00:00
Adam Cooke
6ad56ee9c9 style(rubocop): Lint/IneffectiveAccessModifier 2024-02-10 23:03:28 +00:00
Adam Cooke
c558f1c69c style(rubocop): Style/NumericPredicate 2024-02-10 22:59:30 +00:00
Adam Cooke
7119e8642d style(rubocop): Lint/ShadowingOuterLocalVariable 2024-02-10 22:51:09 +00:00
Adam Cooke
bd85920565 style(rubocop): Style/WordArray 2024-02-10 22:39:43 +00:00
Adam Cooke
129dffab9e style(rubocop): Style/MutableConstant 2024-02-10 17:34:29 +00:00
Adam Cooke
d508772a40 style(rubocop): disable Style/StringConcatenation cop 2024-02-10 17:30:32 +00:00
Adam Cooke
b0ac9ef0b9 style(rubocop): relax method length and block nexting for now 2024-02-10 17:26:45 +00:00
Adam Cooke
a5d5ba5326 style(rubocop): Layout/MultilineMethodCallBraceLayout 2024-02-10 17:25:45 +00:00
Adam Cooke
919a60116c style(rubocop): Naming/FileName 2024-02-10 17:24:37 +00:00
Adam Cooke
0cf35a8392 style(rubocop): Layout/EmptyLines 2024-02-10 17:23:24 +00:00
Adam Cooke
12a5ef3279 style(rubocop): Lint/RedundantStringCoercion 2024-02-10 17:22:59 +00:00
Adam Cooke
0966b44018 style(rubocop): Lint/ShadowedException 2024-02-10 17:21:54 +00:00
Adam Cooke
389ea77050 style(rubocop): Security/YAMLLoad 2024-02-10 17:21:08 +00:00
Adam Cooke
ee94e4e1a0 style(rubocop): Lint/UnusedBlockArgument 2024-02-10 17:20:13 +00:00
Adam Cooke
7590a46234 style(rubocop): Lint/UselessAssignment 2024-02-10 17:18:24 +00:00
Adam Cooke
25d7d66b47 test: FactoryBot.lint will lint all registered factories 2024-02-10 17:18:24 +00:00
Adam Cooke
cfd8d63321 style(rubocop): Layout/EmptyLinesAroundBlockBody 2024-02-10 17:18:24 +00:00
Adam Cooke
1cf665a0cf test: remove FACTORIES_EXCLUDED_FROM_LINT 2024-02-10 17:18:24 +00:00
Adam Cooke
930cf39dba style(rubocop): disable complexity cops for now 2024-02-10 17:18:23 +00:00
Adam Cooke
6d4dea7f7f style(rubocop): update rubocop rules 2024-02-10 17:18:23 +00:00
Adam Cooke
e142d0da5f style(rubocop): Layout/LineLength 2024-02-10 17:18:23 +00:00
Adam Cooke
59f299b704 style(rubocop): Layout/LeadingCommentSpace 2024-02-10 17:18:23 +00:00
Adam Cooke
b4cc81264c style(rubocop): Style/StringLiterals 2024-02-10 17:18:23 +00:00
Adam Cooke
0e4ed5ca03 style(rubocop): Layout/EmptyLineAfterMagicComment 2024-02-10 17:18:23 +00:00
Adam Cooke
6ab36c09c9 style(rubocop): Style/FrozenStringLiteralComment 2024-02-10 17:18:22 +00:00
Adam Cooke
ba5bfbd6a0 fix: fix bug with received header in SMTP server 2024-02-10 17:17:06 +00:00
Adam Cooke
97a328419b Merge pull request #2786 from postalserver/privacy-mode 2024-02-07 10:12:37 +00:00
Adam Cooke
ed2e62b94f feat: remove strip_received_headers config option
This previously removed all Received headers which were sent to the smtp
server when enabled. This is not something that should be happening.
2024-02-07 09:45:12 +00:00
Adam Cooke
15f9671b66 feat: privacy mode
Adds support for hiding IP addresses & hostnames associated with clients sending
authenticated mail in to Postal over SMTP and HTTP
2024-02-07 09:45:09 +00:00
237 ملفات معدلة مع 2226 إضافات و607 حذوفات

عرض الملف

@@ -1,3 +1,3 @@
{
".": "2.2.2"
".": "2.3.0"
}

عرض الملف

@@ -1,35 +1,175 @@
inherit_from:
- https://dev.k.io/rubocop/rubocop.rails.yml
AllCops:
TargetRubyVersion: 3.0
NewCops: enable
Exclude:
- "bin/*"
- "db/schema.rb"
# Fixes missing gem exception when running Rubocop on GitHub Actions.
- "vendor/bundle/**/*"
# Always use double quotes
Style/StringLiterals:
EnforcedStyle: double_quotes
AutoCorrect: true
Style/WordArray:
# We prefer arrays of symbols to look like an array of symbols.
# For example: [:one, :two, :three] as opposed to %i[one two three]
Style/SymbolArray:
EnforcedStyle: brackets
Layout/LineLength:
# There should always be empty lines inside a class. For example
#
# class MyExample
#
# def some_method
# end
#
# end
Layout/EmptyLinesAroundClassBody:
EnforcedStyle: empty_lines
# We want to keep attr_* definitions separated on their own lines, rather than
# all of them collapsed into a single attr_* call. The collapsed/grouped variant
# is harder to read, and harder to see what's been changed in diffs.
Style/AccessorGrouping:
Enabled: false
# Blocks are slightly different to classes, in these cases there should
# not be new lines around the contents of the block.
#
# proc do
# # Do something
# end
Layout/EmptyLinesAroundBlockBody:
EnforcedStyle: no_empty_lines
# Modules are the same as classes unless they're being used for namespacing
# purposes in which case there should not be new lines.
Layout/EmptyLinesAroundModuleBody:
EnforcedStyle: empty_lines_except_namespace
# Space is required following -> when writing a lambda:
#
# somethign = -> (var) { block }
Layout/SpaceInLambdaLiteral:
EnforcedStyle: require_space
Layout/FirstHashElementIndentation:
Enabled: false
# We don't mind setting assignments in conditions so this has been disabled to
# allow `if something = something_else` without worrying about brackets.
Lint/AssignmentInCondition:
Enabled: false
# Top level documentation is quite rare...
Style/Documentation:
Enabled: false
# We want to allow inner slashes in a regexp to be used when using /xxx/ form.
Style/RegexpLiteral:
AllowInnerSlashes: true
# Blocks of if statements are perfectly fine and usually more readable than
# putting everything onto a single line just because we can.
Style/IfUnlessModifier:
Enabled: false
# We prefer assignments to happen within the condition rather than setting a
# variable to the result of a condition.
Style/ConditionalAssignment:
EnforcedStyle: assign_inside_condition
IncludeTernaryExpressions: false
# Empty methods should not be compacted onto a single line
Style/EmptyMethod:
EnforcedStyle: expanded
# As above, just flag them.
Lint/UnusedBlockArgument:
AutoCorrect: false
# While we don't want to make heavy use of get_ or set_ methods we do often need
# to use these when we want to refer to actually getting or setting something
# (usually from another API).
Naming/AccessorMethodName:
Enabled: false
# If we want a boolean called :true, we should be allowed that. These are likely
# not mistakes.
Lint/BooleanSymbol:
Enabled: false
# Using block.map(&:upcase) is not always the neatest way to show something. For
# example if you have a block that just calls one thing, you don't want it
# collapsed.
#
# action do |user|
# user.delete
# end
#
# This should be action(&:delete) because it is not clear what is actually
# happening without the context of knowing what the inner variable should be
# called.
Style/SymbolProc:
Enabled: false
# Allow a maxmium of 5 arguments and don't include keyword arguments
Metrics/ParameterLists:
Max: 5
CountKeywordArgs: false
# This cop checks for chaining of a block after another block that spans multiple lines.
Style/MultilineBlockChain:
Exclude:
- "spec/**/*.rb"
Metrics/AbcSize:
Enabled: false
Style/FrozenStringLiteralComment:
Enabled: true
SafeAutoCorrect: true
Naming/PredicateName:
Enabled: false
Layout/LineLength:
# We want to reduce this back down to 120 but there are a fair number of offences
# of this which need addressing individually and carefully.
Max: 200
Metrics/PerceivedComplexity:
# As above, we want to enable this again in the future, but for now we'll just
# disable it entirely.
Enabled: false
Metrics/CyclomaticComplexity:
# As above.
Enabled: false
Metrics/MethodLength:
# As above.
Enabled: false
Metrics/BlockNesting:
# As above.
Enabled: false
Style/StringConcatenation:
Enabled: false
Metrics/BlockLength:
Enabled: false
Metrics/ClassLength:
Enabled: false
Metrics/CyclomaticComplexity:
Enabled: false
Metrics/MethodLength:
Enabled: false
Metrics/ModuleLength:
Enabled: false
Metrics/PerceivedComplexity:
Lint/UnusedMethodArgument:
Enabled: false
Lint/MissingSuper:
Style/SpecialGlobalVars:
Enabled: false

عرض الملف

@@ -2,6 +2,90 @@
This file contains all the latest changes and updates to Postal.
## [2.3.0](https://github.com/postalserver/postal/compare/2.2.2...2.3.0) (2024-02-13)
### Features
* privacy mode ([15f9671](https://github.com/postalserver/postal/commit/15f9671b667cf369255aaa27ee4257267990095c))
* remove strip_received_headers config option ([ed2e62b](https://github.com/postalserver/postal/commit/ed2e62b94fe76d7aeca0ede98f11a1c4f94c5996))
### Bug Fixes
* add ruby platform to gemfile ([1fceef7](https://github.com/postalserver/postal/commit/1fceef7cea76352fd6166fb3f1e8d0ff8591078e))
* explicitly disable TLS & starttls for unknown SSL modes ([42ab5b3](https://github.com/postalserver/postal/commit/42ab5b3a6b21992c89f8479137699dc9090f0ccc)), closes [#2564](https://github.com/postalserver/postal/issues/2564)
* fix bug with received header in SMTP server ([ba5bfbd](https://github.com/postalserver/postal/commit/ba5bfbd6a0af9ea33bedb2948822417bd1a3fbc5))
* retry mysql connections on message DB pool ([f9f7fb3](https://github.com/postalserver/postal/commit/f9f7fb30fee46b661b6dccde4362383ea591532b))
* use correct method for disconnecting smtp connections ([7c23994](https://github.com/postalserver/postal/commit/7c23994d243ec7d9a17ee053f8c3fa8de0a33097))
### Styles
* **rubocop:** disable complexity cops for now ([930cf39](https://github.com/postalserver/postal/commit/930cf39dba37401f90e293c938dee07daf3d9a31))
* **rubocop:** disable Style/SpecialGlobalVars ([be97f43](https://github.com/postalserver/postal/commit/be97f4330897f96085eb29ed7019b1a3e50af88e))
* **rubocop:** disable Style/StringConcatenation cop ([d508772](https://github.com/postalserver/postal/commit/d508772a40ef26e5c3a8304aa1f2b8c7985081bd))
* **rubocop:** Layout/* ([0e0aca0](https://github.com/postalserver/postal/commit/0e0aca06c90f6d2f4db1c4090a35c4537c76e13a))
* **rubocop:** Layout/EmptyLineAfterMagicComment ([0e4ed5c](https://github.com/postalserver/postal/commit/0e4ed5ca0393f9a56e1efa7ae377d2e4b876bfe1))
* **rubocop:** Layout/EmptyLines ([0cf35a8](https://github.com/postalserver/postal/commit/0cf35a83926d499a279775bcc32dd4ea79b7a8c9))
* **rubocop:** Layout/EmptyLinesAroundBlockBody ([cfd8d63](https://github.com/postalserver/postal/commit/cfd8d63321d1821aad7fa9d6b8462c3d551aca61))
* **rubocop:** Layout/LeadingCommentSpace ([59f299b](https://github.com/postalserver/postal/commit/59f299b704533488b74075beb8692397eb434aab))
* **rubocop:** Layout/LineLength ([e142d0d](https://github.com/postalserver/postal/commit/e142d0da5fbee19e6f9f1741ff9dee0a2d7dd169))
* **rubocop:** Layout/MultilineMethodCallBraceLayout ([a5d5ba5](https://github.com/postalserver/postal/commit/a5d5ba5326728413bb95456e92c854977d225a7f))
* **rubocop:** Lint/DuplicateBranch ([a1dc0f7](https://github.com/postalserver/postal/commit/a1dc0f77ac69937d7f30c9401608dfbe66987d45))
* **rubocop:** Lint/DuplicateMethods ([bab6346](https://github.com/postalserver/postal/commit/bab6346239e4f50bdd51101c45f3a0cd66f47096))
* **rubocop:** Lint/IneffectiveAccessModifier ([6ad56ee](https://github.com/postalserver/postal/commit/6ad56ee9c9e5bad19b065fcec3ada3280adbb1f4))
* **rubocop:** Lint/MissingSuper ([4674e63](https://github.com/postalserver/postal/commit/4674e63b5ff84307f5b772e870e88109af2daf52))
* **rubocop:** Lint/RedundantStringCoercion ([12a5ef3](https://github.com/postalserver/postal/commit/12a5ef3279bf6c1e5c38bf7e846de1d17bf98c09))
* **rubocop:** Lint/ShadowedException ([0966b44](https://github.com/postalserver/postal/commit/0966b44018bc1e2f131358635776fcc3b75ee8eb))
* **rubocop:** Lint/ShadowingOuterLocalVariable ([7119e86](https://github.com/postalserver/postal/commit/7119e8642dffeee7a27f90145073e45664ea58d3))
* **rubocop:** Lint/SuppressedException ([278ef08](https://github.com/postalserver/postal/commit/278ef0886ac53e6bed15793301dc69c95a37dbde))
* **rubocop:** Lint/UnderscorePrefixedVariableName ([ec7dcf4](https://github.com/postalserver/postal/commit/ec7dcf4f9a0bdb367a90f1a3b35336909ebc60d7))
* **rubocop:** Lint/UnusedBlockArgument ([ee94e4e](https://github.com/postalserver/postal/commit/ee94e4e1a013bbe8fbdd8ef94f15ed0fa20709ac))
* **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:** 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))
* **rubocop:** Style/ClassAndModuleChildren ([e896f46](https://github.com/postalserver/postal/commit/e896f4689a8fc54979f0a6c2b7ce14746856bad6))
* **rubocop:** Style/For ([04a3483](https://github.com/postalserver/postal/commit/04a34831c74a3a44547f93100c35db650bc4eef6))
* **rubocop:** Style/FrozenStringLiteralComment ([6ab36c0](https://github.com/postalserver/postal/commit/6ab36c09c966eb9a8b8ada52155f74d2537977f2))
* **rubocop:** Style/GlobalStdStream ([75be690](https://github.com/postalserver/postal/commit/75be6907483ea25f828461eb790d3f6f46ca683b))
* **rubocop:** Style/GlobalVars ([157d114](https://github.com/postalserver/postal/commit/157d11457c520147807901b75b3ba22d29172f24))
* **rubocop:** Style/HashEachMethods ([c995027](https://github.com/postalserver/postal/commit/c995027ff53962ae49341372f75e2bf43ecde0d2))
* **rubocop:** Style/HashExcept ([83ac764](https://github.com/postalserver/postal/commit/83ac76451071f097e7197f77fc5ad16e9cf58593))
* **rubocop:** Style/IdenticalConditionalBranches ([6a58ecf](https://github.com/postalserver/postal/commit/6a58ecf605250b8fa891cb14fca0c0e0ce0d7eb9))
* **rubocop:** Style/MissingRespondToMissing ([ffcb707](https://github.com/postalserver/postal/commit/ffcb707247fe2a69905aa6e4dc668abeb9924611))
* **rubocop:** Style/MultilineBlockChain ([c6326a6](https://github.com/postalserver/postal/commit/c6326a6524e6d71d23bc2c256f3f9416c38b0846))
* **rubocop:** Style/MutableConstant ([129dffa](https://github.com/postalserver/postal/commit/129dffab9ed8726ca4066e7052adc699129de2d2))
* **rubocop:** Style/NumericPredicate ([c558f1c](https://github.com/postalserver/postal/commit/c558f1c69ce9498564161d8cef3fcb8213103498))
* **rubocop:** Style/PreferredHashMethods ([013b3ea](https://github.com/postalserver/postal/commit/013b3ea9315c14f24b08574d68e1688f33d78b8d))
* **rubocop:** Style/SafeNavigation ([00a02f2](https://github.com/postalserver/postal/commit/00a02f2655b6e3296ad0e7ea9b9872da936b56ed))
* **rubocop:** Style/SelectByRegexp ([9ce28a4](https://github.com/postalserver/postal/commit/9ce28a427fadf6fafd942e009792be4b5539d40d))
* **rubocop:** Style/StringLiterals ([b4cc812](https://github.com/postalserver/postal/commit/b4cc81264c85d5f0061e5b5121a30d7bdcabc189))
* **rubocop:** Style/WordArray ([bd85920](https://github.com/postalserver/postal/commit/bd8592056573d1c6933d753ed50bdf9a7466e761))
* **rubocop:** update rubocop rules ([6d4dea7](https://github.com/postalserver/postal/commit/6d4dea7f7f0145ff2b99cf2505bc70a3e5925256))
### Miscellaneous Chores
* annotate models ([6214892](https://github.com/postalserver/postal/commit/6214892710e21c2aa29a319d5809f7bdf0d50529))
* silence message DB migrations during provisioning ([c83601a](https://github.com/postalserver/postal/commit/c83601af69f35e338b1f7c10ef7994f74b96f8bf))
### Code Refactoring
* remove reloading on the smtp server ([c3c304e](https://github.com/postalserver/postal/commit/c3c304e98b3274433248792b6403acf63d7a513b))
### Tests
* add initial tests for Postal::SMTPServer::Client ([dece1d4](https://github.com/postalserver/postal/commit/dece1d487ac2fdce104700939a79a5579b60a0cb))
* FactoryBot.lint will lint all registered factories ([25d7d66](https://github.com/postalserver/postal/commit/25d7d66b4709fe5442d554097a6ef074aeb15f72))
* remove FACTORIES_EXCLUDED_FROM_LINT ([1cf665a](https://github.com/postalserver/postal/commit/1cf665a0cf61d1eae3d08bdadf6fccaab6413023))
## [2.2.2](https://github.com/postalserver/postal/compare/2.2.1...2.2.2) (2024-02-06)

11
Gemfile
عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
source "https://rubygems.org"
gem "authie"
gem "autoprefixer-rails"
@@ -10,12 +12,12 @@ gem "clockwork"
gem "dotenv-rails"
gem "dynamic_form"
gem "encrypto_signo"
gem "execjs", "~> 2.7", "< 2.8"
gem "foreman"
gem "gelf"
gem "haml"
gem "hashie"
gem "highline", require: false
gem "execjs", '~> 2.7', "< 2.8"
gem "jwt"
gem "kaminari"
gem "mail"
@@ -28,8 +30,8 @@ gem "puma"
gem "rails", "= 6.1.7.6"
gem "resolv", "~> 0.2.1"
gem "secure_headers"
gem 'sentry-rails'
gem 'sentry-ruby'
gem "sentry-rails"
gem "sentry-ruby"
gem "turbolinks", "~> 5"
group :development, :assets do
@@ -46,9 +48,10 @@ end
group :development do
gem "annotate"
gem "database_cleaner", require: false
gem "factory_bot_rails", "~> 4.0", require: false
gem "factory_bot_rails", require: false
gem "rspec", require: false
gem "rspec-rails", require: false
gem "rubocop"
gem "rubocop-rails"
gem "timecop"
end

عرض الملف

@@ -89,7 +89,7 @@ GEM
coffee-script-source
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.2.2)
concurrent-ruby (1.2.3)
crass (1.0.6)
database_cleaner (2.0.2)
database_cleaner-active_record (>= 2, < 3)
@@ -104,15 +104,17 @@ GEM
dotenv-rails (2.8.1)
dotenv (= 2.8.1)
railties (>= 3.2)
dynamic_form (1.1.4)
dynamic_form (1.3.1)
actionview (> 5.2.0)
activemodel (> 5.2.0)
encrypto_signo (1.0.0)
erubi (1.12.0)
execjs (2.7.0)
factory_bot (4.11.1)
activesupport (>= 3.0.0)
factory_bot_rails (4.11.1)
factory_bot (~> 4.11.1)
railties (>= 3.0.0)
factory_bot (6.4.6)
activesupport (>= 5.0.0)
factory_bot_rails (6.4.3)
factory_bot (~> 6.4)
railties (>= 5.0.0)
ffi (1.15.5)
foreman (0.87.2)
gelf (3.1.0)
@@ -125,7 +127,7 @@ GEM
tilt
hashie (5.0.0)
highline (2.1.0)
i18n (1.12.0)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
jquery-rails (4.5.1)
rails-dom-testing (>= 1, < 3)
@@ -145,9 +147,9 @@ GEM
activerecord
kaminari-core (= 1.2.2)
kaminari-core (1.2.2)
loofah (2.19.1)
loofah (2.22.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
nokogiri (>= 1.12.0)
mail (2.8.1)
mini_mime (>= 0.1.1)
net-imap
@@ -157,7 +159,7 @@ GEM
method_source (1.0.0)
mini_mime (1.1.2)
mini_portile2 (2.8.5)
minitest (5.18.0)
minitest (5.22.2)
moonrope (2.0.2)
deep_merge (~> 1.0)
json
@@ -190,7 +192,7 @@ GEM
puma (6.4.2)
nio4r (~> 2.0)
racc (1.7.3)
rack (2.2.6.4)
rack (2.2.8)
rack-test (2.1.0)
rack (>= 1.3)
rails (6.1.7.6)
@@ -208,11 +210,13 @@ GEM
bundler (>= 1.15.0)
railties (= 6.1.7.6)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
rails-html-sanitizer (1.5.0)
loofah (~> 2.19, >= 2.19.1)
rails-html-sanitizer (1.6.0)
loofah (~> 2.21)
nokogiri (~> 1.14)
railties (6.1.7.6)
actionpack (= 6.1.7.6)
activesupport (= 6.1.7.6)
@@ -220,7 +224,7 @@ GEM
rake (>= 12.2)
thor (~> 1.0)
rainbow (3.1.1)
rake (13.0.6)
rake (13.1.0)
rbtree (0.4.6)
regexp_parser (2.7.0)
resolv (0.2.2)
@@ -292,8 +296,9 @@ GEM
activesupport (>= 5.2)
sprockets (>= 3.0.0)
temple (0.10.0)
thor (1.2.1)
thor (1.3.0)
tilt (2.1.0)
timecop (0.9.8)
timeout (0.3.2)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
@@ -306,10 +311,11 @@ GEM
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
zeitwerk (2.6.7)
zeitwerk (2.6.13)
PLATFORMS
arm64-darwin-22
arm64-darwin-23
ruby
x86_64-linux
@@ -330,7 +336,7 @@ DEPENDENCIES
dynamic_form
encrypto_signo
execjs (~> 2.7, < 2.8)
factory_bot_rails (~> 4.0)
factory_bot_rails
foreman
gelf
haml
@@ -356,6 +362,7 @@ DEPENDENCIES
secure_headers
sentry-rails
sentry-ruby
timecop
turbolinks (~> 5)
uglifier (>= 1.3.0)

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
authenticator :server do
friendly_name "Server Authenticator"
header "X-Server-API-Key", "The API token for a server that you wish to authenticate with.", example: "f29a45f0d4e1744ebaee"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
controller :messages do
friendly_name "Messages API"
description "This API allows you to access message details"
@@ -12,7 +14,7 @@ controller :messages do
action do
begin
message = identity.server.message(params.id)
rescue Postal::MessageDB::Message::NotFound => e
rescue Postal::MessageDB::Message::NotFound
error "MessageNotFound", id: params.id
end
structure :message, message, return: true
@@ -28,7 +30,7 @@ controller :messages do
action do
begin
message = identity.server.message(params.id)
rescue Postal::MessageDB::Message::NotFound => e
rescue Postal::MessageDB::Message::NotFound
error "MessageNotFound", id: params.id
end
message.deliveries.map do |d|

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
controller :send do
friendly_name "Send API"
description "This API allows you to send messages"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
structure :delivery do
basic :id
basic :status

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
structure :message do
basic :id
basic :token
@@ -5,9 +7,9 @@ structure :message do
expansion(:status) do
{
status: o.status,
last_delivery_attempt: o.last_delivery_attempt ? o.last_delivery_attempt.to_f : nil,
last_delivery_attempt: o.last_delivery_attempt&.to_f,
held: o.held,
hold_expiry: o.hold_expiry ? o.hold_expiry.to_f : nil
hold_expiry: o.hold_expiry&.to_f
}
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class AddressEndpointsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require "authie/session"
class ApplicationController < ActionController::Base
@@ -46,11 +48,7 @@ class ApplicationController < ActionController::Base
helper_method :page_title
def redirect_to_with_return_to(url, *args)
if params[:return_to].blank? || !params[:return_to].starts_with?("/")
redirect_to url_with_return_to(url), *args
else
redirect_to url_with_return_to(url), *args
end
redirect_to url_with_return_to(url), *args
end
def set_timezone

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module WithinOrganization
extend ActiveSupport::Concern

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class CredentialsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class DomainsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class HelpController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class HTTPEndpointsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class IPAddressesController < ApplicationController
before_action :admin_required

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class IPPoolRulesController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class IPPoolsController < ApplicationController
before_action :admin_required
@@ -31,7 +33,7 @@ class IPPoolsController < ApplicationController
def destroy
@ip_pool.destroy
redirect_to_with_json :ip_pools, notice: "IP pool has been removed successfully."
rescue ActiveRecord::DeleteRestrictionError => e
rescue ActiveRecord::DeleteRestrictionError
redirect_to_with_json [:edit, @ip_pool], alert: "IP pool cannot be removed because it still has associated addresses or servers."
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class MessagesController < ApplicationController
include WithinOrganization
@@ -186,7 +188,7 @@ class MessagesController < ApplicationController
if qs[:before]
begin
options[:where][:timestamp][:less_than] = get_time_from_string(qs[:before]).to_f
rescue TimeUndetermined => e
rescue TimeUndetermined
flash.now[:alert] = "Couldn't determine time for before from '#{qs[:before]}'"
end
end
@@ -194,7 +196,7 @@ class MessagesController < ApplicationController
if qs[:after]
begin
options[:where][:timestamp][:greater_than] = get_time_from_string(qs[:after]).to_f
rescue TimeUndetermined => e
rescue TimeUndetermined
flash.now[:alert] = "Couldn't determine time for after from '#{qs[:after]}'"
end
end
@@ -220,6 +222,7 @@ class MessagesController < ApplicationController
time = Chronic.parse(string, context: :past)
end
rescue StandardError
time = nil
end
raise TimeUndetermined, "Couldn't determine a suitable time from '#{string}'" if time.nil?

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class OrganizationIPPoolsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class OrganizationsController < ApplicationController
before_action :admin_required, only: [:new, :create, :delete, :destroy]

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class RoutesController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ServersController < ApplicationController
include WithinOrganization
@@ -41,7 +43,12 @@ class ServersController < ApplicationController
def update
extra_params = [:spam_threshold, :spam_failure_threshold, :postmaster_address]
extra_params += [:send_limit, :allow_sender, :log_smtp_data, :outbound_spam_threshold, :message_retention_days, :raw_message_retention_days, :raw_message_retention_size] if current_user.admin?
if current_user.admin?
extra_params += [:send_limit, :allow_sender, :privacy_mode, :log_smtp_data, :outbound_spam_threshold,
:message_retention_days, :raw_message_retention_days, :raw_message_retention_size]
end
if @server.update(safe_params(*extra_params))
redirect_to_with_json organization_server_path(organization, @server), notice: "Server settings have been updated"
else

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class SessionsController < ApplicationController
layout "sub"
@@ -8,7 +10,7 @@ class SessionsController < ApplicationController
login(User.authenticate(params[:email_address], params[:password]))
flash[:remember_login] = true
redirect_to_with_return_to root_path
rescue Postal::Errors::AuthenticationError => e
rescue Postal::Errors::AuthenticationError
flash.now[:alert] = "The credentials you've provided are incorrect. Please check and try again."
render "new"
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class SMTPEndpointsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class TrackDomainsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class UserController < ApplicationController
skip_before_action :login_required, only: [:new, :create, :join]
@@ -69,7 +71,9 @@ class UserController < ApplicationController
if @user.save
if email_changed
redirect_to_with_json verify_path(return_to: settings_path), notice: "Your settings have been updated successfully. As you've changed, your e-mail address you'll need to verify it before you can continue."
redirect_to_with_json verify_path(return_to: settings_path),
notice: "Your settings have been updated successfully. As you've changed, your e-mail " \
"address you'll need to verify it before you can continue."
else
redirect_to_with_json settings_path, notice: "Your settings have been updated successfully."
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class UsersController < ApplicationController
before_action :admin_required

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class WebhooksController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module ApplicationHelper
def format_delivery_details(server, text)
@@ -28,7 +30,7 @@ module ApplicationHelper
server_domains = server.domains.verified.order(:name)
unless server_domains.empty?
s << "<optgroup label='Server Domains'>"
for domain in server_domains
server_domains.each do |domain|
selected = domain == selected_domain ? "selected='selected'" : ""
s << "<option value='#{domain.id}' #{selected}>#{domain.name}</option>"
end
@@ -38,7 +40,7 @@ module ApplicationHelper
organization_domains = server.organization.domains.verified.order(:name)
unless organization_domains.empty?
s << "<optgroup label='Organization Domains'>"
for domain in organization_domains
organization_domains.each do |domain|
selected = domain == selected_domain ? "selected='selected'" : ""
s << "<option value='#{domain.id}' #{selected}>#{domain.name}</option>"
end
@@ -54,7 +56,7 @@ module ApplicationHelper
http_endpoints = server.http_endpoints.order(:name).to_a
if http_endpoints.present?
s << "<optgroup label='HTTP Endpoints'>"
for endpoint in http_endpoints
http_endpoints.each do |endpoint|
value = "#{endpoint.class}##{endpoint.uuid}"
selected = value == selected_value ? "selected='selected'" : ""
s << "<option value='#{value}' #{selected}>#{endpoint.description}</option>"
@@ -65,7 +67,7 @@ module ApplicationHelper
smtp_endpoints = server.smtp_endpoints.order(:name).to_a
if smtp_endpoints.present?
s << "<optgroup label='SMTP Endpoints'>"
for endpoint in smtp_endpoints
smtp_endpoints.each do |endpoint|
value = "#{endpoint.class}##{endpoint.uuid}"
selected = value == selected_value ? "selected='selected'" : ""
s << "<option value='#{value}' #{selected}>#{endpoint.description}</option>"
@@ -76,7 +78,7 @@ module ApplicationHelper
address_endpoints = server.address_endpoints.order(:address).to_a
if address_endpoints.present?
s << "<optgroup label='Address Endpoints'>"
for endpoint in address_endpoints
address_endpoints.each do |endpoint|
value = "#{endpoint.class}##{endpoint.uuid}"
selected = value == selected_value ? "selected='selected'" : ""
s << "<option value='#{value}' #{selected}>#{endpoint.address}</option>"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ActionDeletionJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ActionDeletionsJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class CheckAllDNSJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require "authie/session"
class CleanupAuthieSessionsJob < Postal::Job

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ExpireHeldMessagesJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ProcessMessageRetentionJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class PruneSuppressionListsJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class PruneWebhookRequestsJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class RequeueWebhooksJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class SendNotificationsJob < Postal::Job
def perform

عرض الملف

@@ -1,16 +1,17 @@
# frozen_string_literal: true
class SendWebhookJob < Postal::Job
def perform
if server = Server.find(params["server_id"])
new_items = {}
if params["payload"]
for key, value in params["payload"]
next unless key.to_s =~ /\A_(\w+)/
params["payload"]&.each do |key, value|
next unless key.to_s =~ /\A_(\w+)/
begin
new_items[::Regexp.last_match(1)] = server.message_db.message(value.to_i).webhook_hash
rescue Postal::MessageDB::Message::NotFound
end
begin
new_items[::Regexp.last_match(1)] = server.message_db.message(value.to_i).webhook_hash
rescue Postal::MessageDB::Message::NotFound
# No message found, don't do any replacement
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class SleepJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class TidyRawMessagesJob < Postal::Job
def perform

عرض الملف

@@ -1,5 +1,8 @@
# frozen_string_literal: true
class UnqueueMessageJob < Postal::Job
# rubocop:disable Layout/LineLength
def perform
if original_message = QueuedMessage.find_by_id(params["id"])
if original_message.acquire_lock
@@ -91,11 +94,11 @@ class UnqueueMessageJob < Postal::Job
log "#{log_prefix} Message is a bounce"
original_messages = queued_message.message.original_messages
unless original_messages.empty?
for original_message in queued_message.message.original_messages
queued_message.message.update(bounce_for_id: original_message.id, domain_id: original_message.domain_id)
queued_message.message.create_delivery("Processed", details: "This has been detected as a bounce message for <msg:#{original_message.id}>.")
original_message.bounce!(queued_message.message)
log "#{log_prefix} Bounce linked with message #{original_message.id}"
queued_message.message.original_messages.each do |orig_msg|
queued_message.message.update(bounce_for_id: orig_msg.id, domain_id: orig_msg.domain_id)
queued_message.message.create_delivery("Processed", details: "This has been detected as a bounce message for <msg:#{orig_msg.id}>.")
orig_msg.bounce!(queued_message.message)
log "#{log_prefix} Bounce linked with message #{orig_msg.id}"
end
queued_message.destroy
next
@@ -421,15 +424,17 @@ class UnqueueMessageJob < Postal::Job
end
rescue StandardError => e
log "#{log_prefix} Internal error: #{e.class}: #{e.message}"
e.backtrace.each { |e| log("#{log_prefix} #{e}") }
e.backtrace.each { |line| log("#{log_prefix} #{line}") }
queued_message.retry_later
log "#{log_prefix} Queued message was unlocked"
if defined?(Sentry)
Sentry.capture_exception(e, extra: { job_id: self.id, server_id: queued_message.server_id, message_id: queued_message.message_id })
end
if queued_message.message
queued_message.message.create_delivery("Error", details: "An internal error occurred while sending this message. This message will be retried automatically. If this persists, contact support for assistance.", output: "#{e.class}: #{e.message}", log_id: "J-#{self.id}")
end
queued_message.message&.create_delivery("Error",
details: "An internal error occurred while sending " \
"this message. This message will be retried " \
"automatically.",
output: "#{e.class}: #{e.message}", log_id: "J-#{self.id}")
end
end
@@ -446,9 +451,11 @@ class UnqueueMessageJob < Postal::Job
nil
end
end
# rubocop:enable Layout/LineLength
private
# rubocop:disable Naming/MemoizedInstanceVariableName
def cached_sender(klass, *args)
@sender ||= begin
sender = klass.new(*args)
@@ -456,5 +463,6 @@ class UnqueueMessageJob < Postal::Job
sender
end
end
# rubocop:enable Naming/MemoizedInstanceVariableName
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class WebhookDeliveryJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class AppMailer < ApplicationMailer
def verify_email_address(user)

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ApplicationMailer < ActionMailer::Base
default from: "#{Postal.smtp_from_name} <#{Postal.smtp_from_address}>"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: additional_route_endpoints
@@ -35,9 +37,7 @@ class AdditionalRouteEndpoint < ApplicationRecord
end
def _endpoint=(value)
if value.blank?
self.endpoint = nil
elsif value =~ /\#/
if value && value =~ /\#/
class_name, id = value.split("#", 2)
unless Route::ENDPOINT_TYPES.include?(class_name)
raise Postal::Error, "Invalid endpoint class name '#{class_name}'"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: address_endpoints

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module HasAuthentication
extend ActiveSupport::Concern
@@ -42,18 +44,4 @@ module HasAuthentication
end
class Postal::Errors::AuthenticationError < Postal::Error
attr_reader :error
def initialize(error)
@error = error
end
def to_s
"Authentication Failed: #{@error}"
end
end
# -*- SkipSchemaAnnotations

عرض الملف

@@ -1,9 +1,11 @@
# frozen_string_literal: true
require "resolv"
module HasDNSChecks
def dns_ok?
spf_status == "OK" && dkim_status == "OK" && ["OK", "Missing"].include?(mx_status) && ["OK", "Missing"].include?(return_path_status)
spf_status == "OK" && dkim_status == "OK" && %w[OK Missing].include?(mx_status) && %w[OK Missing].include?(return_path_status)
end
def dns_checked?
@@ -42,12 +44,12 @@ module HasDNSChecks
def check_spf_record
result = resolver.getresources(name, Resolv::DNS::Resource::IN::TXT)
spf_records = result.map(&:data).select { |d| d =~ /\Av=spf1/ }
spf_records = result.map(&:data).grep(/\Av=spf1/)
if spf_records.empty?
self.spf_status = "Missing"
self.spf_error = "No SPF record exists for this domain"
else
suitable_spf_records = spf_records.select { |d| d =~ /include:\s*#{Regexp.escape(Postal.config.dns.spf_include)}/ }
suitable_spf_records = spf_records.grep(/include:\s*#{Regexp.escape(Postal.config.dns.spf_include)}/)
if suitable_spf_records.empty?
self.spf_status = "Invalid"
self.spf_error = "An SPF record exists but it doesn't include #{Postal.config.dns.spf_include}"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module HasMessage
def self.included(base)
@@ -18,7 +20,7 @@ module HasMessage
def include_message
queued_messages = all.to_a
server_ids = queued_messages.map(&:server_id).uniq
if server_ids.size == 0
if server_ids.empty?
return []
elsif server_ids.size > 1
raise Postal::Error, "'include_message' can only be used on collections of messages from the same server"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module HasSoftDestroy
def self.included(base)

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module HasUUID
def self.included(base)

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: credentials
@@ -21,7 +23,7 @@ class Credential < ApplicationRecord
belongs_to :server
TYPES = ["SMTP", "API", "SMTP-IP"]
TYPES = %w[SMTP API SMTP-IP].freeze
validates :key, presence: true, uniqueness: { case_sensitive: false }
validates :type, inclusion: { in: TYPES }

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: domains
@@ -42,15 +44,14 @@ class Domain < ApplicationRecord
include HasDNSChecks
VERIFICATION_EMAIL_ALIASES = ["webmaster", "postmaster", "admin", "administrator", "hostmaster"]
VERIFICATION_EMAIL_ALIASES = %w[webmaster postmaster admin administrator hostmaster].freeze
VERIFICATION_METHODS = %w[DNS Email].freeze
belongs_to :server, optional: true
belongs_to :owner, optional: true, polymorphic: true
has_many :routes, dependent: :destroy
has_many :track_domains, dependent: :destroy
VERIFICATION_METHODS = ["DNS", "Email"]
validates :name, presence: true, format: { with: /\A[a-z0-9\-.]*\z/ }, uniqueness: { case_sensitive: false, scope: [:owner_type, :owner_id], message: "is already added" }
validates :verification_method, inclusion: { in: VERIFICATION_METHODS }
@@ -83,8 +84,8 @@ class Domain < ApplicationRecord
def parent_domains
parts = name.split(".")
parts[0, parts.size - 1].each_with_index.map do |p, i|
parts[i..-1].join(".")
parts[0, parts.size - 1].each_with_index.map do |_, i|
parts[i..].join(".")
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: http_endpoints
@@ -29,8 +31,8 @@ class HTTPEndpoint < ApplicationRecord
has_many :routes, as: :endpoint
has_many :additional_route_endpoints, dependent: :destroy, as: :endpoint
ENCODINGS = ["BodyAsJSON", "FormData"]
FORMATS = ["Hash", "RawMessage"]
ENCODINGS = %w[BodyAsJSON FormData].freeze
FORMATS = %w[Hash RawMessage].freeze
before_destroy :update_routes

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class IncomingMessagePrototype
attr_accessor :to
@@ -22,13 +24,14 @@ class IncomingMessagePrototype
end
def route
@routes ||= if @to.present?
uname, domain = @to.split("@", 2)
uname, tag = uname.split("+", 2)
@server.routes.includes(:domain).where(domains: { name: domain }, name: uname).first
end
@route ||= if @to.present?
uname, domain = @to.split("@", 2)
uname, _tag = uname.split("+", 2)
@server.routes.includes(:domain).where(domains: { name: domain }, name: uname).first
end
end
# rubocop:disable Lint/DuplicateMethods
def attachments
(@attachments || []).map do |attachment|
{
@@ -38,6 +41,7 @@ class IncomingMessagePrototype
}
end
end
# rubocop:enable Lint/DuplicateMethods
def create_messages
if valid?
@@ -91,7 +95,7 @@ class IncomingMessagePrototype
content: attachment[:data]
}
end
mail.header["Received"] = "from #{@source_type} (#{@ip} [#{@ip}]) by Postal with HTTP; #{Time.now.utc.rfc2822}"
mail.header["Received"] = Postal::ReceivedHeader.generate(@server, @source_type, @ip, :http)
mail.to_s
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: ip_addresses

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: ip_pools

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: ip_pool_rules
@@ -66,18 +68,22 @@ class IPPoolRule < ApplicationRecord
errors.add :ip_pool_id, "must belong to the organization"
end
def self.address_matches?(condition, address)
address = Postal::Helpers.strip_name_from_address(address)
if condition =~ /@/
parts = address.split("@")
domain = parts.pop
uname = parts.join("@")
uname, = uname.split("+", 2)
condition == "#{uname}@#{domain}"
else
# Match as a domain
condition == address.split("@").last
class << self
def address_matches?(condition, address)
address = Postal::Helpers.strip_name_from_address(address)
if condition =~ /@/
parts = address.split("@")
domain = parts.pop
uname = parts.join("@")
uname, = uname.split("+", 2)
condition == "#{uname}@#{domain}"
else
# Match as a domain
condition == address.split("@").last
end
end
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: organizations
@@ -23,7 +25,7 @@
class Organization < ApplicationRecord
RESERVED_PERMALINKS = ["new", "edit", "remove", "delete", "destroy", "admin", "mail", "org", "server"]
RESERVED_PERMALINKS = %w[new edit remove delete destroy admin mail org server].freeze
INITIAL_QUOTA = 10
INITIAL_SUPER_QUOTA = 10_000
@@ -48,7 +50,7 @@ class Organization < ApplicationRecord
has_many :ip_pool_rules, dependent: :destroy, as: :owner
after_create do
if pool = IPPool.default
if IPPool.default
ip_pools << IPPool.default
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: organization_ip_pools

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: organization_users

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require "resolv"
class OutgoingMessagePrototype
@@ -47,13 +49,11 @@ class OutgoingMessagePrototype
end
def find_domain
@domain ||= begin
domain = @server.authenticated_domain_for_address(@from)
if @server.allow_sender? && domain.nil?
domain = @server.authenticated_domain_for_address(@sender)
end
domain || :none
domain = @server.authenticated_domain_for_address(@from)
if @server.allow_sender? && domain.nil?
domain = @server.authenticated_domain_for_address(@sender)
end
domain || :none
end
def to_addresses
@@ -93,6 +93,7 @@ class OutgoingMessagePrototype
@errors || {}
end
# rubocop:disable Lint/DuplicateMethods
def attachments
(@attachments || []).map do |attachment|
{
@@ -102,6 +103,7 @@ class OutgoingMessagePrototype
}
end
end
# rubocop:enable Lint/DuplicateMethods
def validate
@errors = []
@@ -135,7 +137,7 @@ class OutgoingMessagePrototype
end
if attachments.present?
attachments.each_with_index do |attachment, index|
attachments.each do |attachment|
if attachment[:name].blank?
@errors << "AttachmentMissingName" unless @errors.include?("AttachmentMissingName")
elsif attachment[:data].blank?
@@ -175,7 +177,7 @@ class OutgoingMessagePrototype
content: attachment[:data]
}
end
mail.header["Received"] = "from #{@source_type} (#{resolved_hostname} [#{@ip}]) by Postal with HTTP; #{Time.now.utc.rfc2822}"
mail.header["Received"] = Postal::ReceivedHeader.generate(@server, @source_type, @ip, :http)
mail.message_id = "<#{@message_id}>"
mail.to_s
end
@@ -196,12 +198,4 @@ class OutgoingMessagePrototype
{ id: message.id, token: message.token }
end
def resolved_hostname
@resolved_hostname ||= begin
Resolv.new.getname(@ip)
rescue StandardError
@ip
end
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: queued_messages

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: routes
@@ -22,7 +24,9 @@
class Route < ApplicationRecord
MODES = ["Endpoint", "Accept", "Hold", "Bounce", "Reject"]
MODES = %w[Endpoint Accept Hold Bounce Reject].freeze
SPAM_MODES = %w[Mark Quarantine Fail].freeze
ENDPOINT_TYPES = %w[SMTPEndpoint HTTPEndpoint AddressEndpoint].freeze
include HasUUID
@@ -31,9 +35,6 @@ class Route < ApplicationRecord
belongs_to :endpoint, polymorphic: true, optional: true
has_many :additional_route_endpoints, dependent: :destroy
SPAM_MODES = ["Mark", "Quarantine", "Fail"]
ENDPOINT_TYPES = ["SMTPEndpoint", "HTTPEndpoint", "AddressEndpoint"]
validates :name, presence: true, format: /\A(([a-z0-9\-.]*)|(\*)|(__returnpath__))\z/
validates :spam_mode, inclusion: { in: SPAM_MODES }
validates :endpoint, presence: { if: proc { mode == "Endpoint" } }
@@ -115,7 +116,7 @@ class Route < ApplicationRecord
if route.save
seen << route.id
else
route.errors.each do |field, message|
route.errors.each do |_, message|
errors.add :base, message
end
raise ActiveRecord::RecordInvalid
@@ -200,7 +201,7 @@ class Route < ApplicationRecord
if route = Route.includes(:domain).where(domains: { name: domain.name }, name: name).where.not(id: id).first
errors.add :name, "is configured on the #{route.server.full_permalink} mail server"
end
elsif route = Route.where(name: "__returnpath__").where.not(id: id).exists?
elsif Route.where(name: "__returnpath__").where.not(id: id).exists?
errors.add :base, "A return path route already exists for this server"
end
end
@@ -218,12 +219,16 @@ class Route < ApplicationRecord
errors.add :base, "Additional routes are not permitted unless the primary route is an actual endpoint"
end
def self.find_by_name_and_domain(name, domain)
route = Route.includes(:domain).where(name: name, domains: { name: domain }).first
if route.nil?
route = Route.includes(:domain).where(name: "*", domains: { name: domain }).first
class << self
def find_by_name_and_domain(name, domain)
route = Route.includes(:domain).where(name: name, domains: { name: domain }).first
if route.nil?
route = Route.includes(:domain).where(name: "*", domains: { name: domain }).first
end
route
end
route
end
end

عرض الملف

@@ -1,35 +1,38 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: servers
#
# id :integer not null, primary key
# organization_id :integer
# uuid :string(255)
# name :string(255)
# mode :string(255)
# ip_pool_id :integer
# created_at :datetime
# updated_at :datetime
# permalink :string(255)
# send_limit :integer
# allow_sender :boolean default(FALSE)
# deleted_at :datetime
# domains_not_to_click_track :text(65535)
# log_smtp_data :boolean default(FALSE)
# message_retention_days :integer
# mode :string(255)
# name :string(255)
# outbound_spam_threshold :decimal(8, 2)
# permalink :string(255)
# postmaster_address :string(255)
# privacy_mode :boolean default(FALSE)
# raw_message_retention_days :integer
# raw_message_retention_size :integer
# allow_sender :boolean default(FALSE)
# token :string(255)
# send_limit :integer
# send_limit_approaching_at :datetime
# send_limit_approaching_notified_at :datetime
# send_limit_exceeded_at :datetime
# send_limit_exceeded_notified_at :datetime
# spam_threshold :decimal(8, 2)
# spam_failure_threshold :decimal(8, 2)
# postmaster_address :string(255)
# spam_threshold :decimal(8, 2)
# suspended_at :datetime
# outbound_spam_threshold :decimal(8, 2)
# domains_not_to_click_track :text(65535)
# suspension_reason :string(255)
# log_smtp_data :boolean default(FALSE)
# token :string(255)
# uuid :string(255)
# created_at :datetime
# updated_at :datetime
# ip_pool_id :integer
# organization_id :integer
#
# Indexes
#
@@ -41,7 +44,8 @@
class Server < ApplicationRecord
RESERVED_PERMALINKS = ["new", "all", "search", "stats", "edit", "manage", "delete", "destroy", "remove"]
RESERVED_PERMALINKS = %w[new all search stats edit manage delete destroy remove].freeze
MODES = %w[Live Development].freeze
include HasUUID
include HasSoftDestroy
@@ -62,8 +66,6 @@ class Server < ApplicationRecord
has_many :track_domains, dependent: :destroy
has_many :ip_pool_rules, dependent: :destroy, as: :owner
MODES = ["Live", "Development"]
random_string :token, type: :chars, length: 6, unique: true, upper_letters_only: true
default_value :permalink, -> { name ? name.parameterize : nil }
default_value :raw_message_retention_days, -> { 30 }
@@ -155,11 +157,11 @@ class Server < ApplicationRecord
time = Time.now.utc
total_outgoing = 0.0
total_bounces = 0.0
message_db.statistics.get(:daily, [:outgoing, :bounces], time, 30).each do |date, stat|
message_db.statistics.get(:daily, [:outgoing, :bounces], time, 30).each do |_, stat|
total_outgoing += stat[:outgoing]
total_bounces += stat[:bounces]
end
total_outgoing == 0 ? 0 : (total_bounces / total_outgoing) * 100
total_outgoing.zero? ? 0 : (total_bounces / total_outgoing) * 100
end
end
@@ -218,6 +220,10 @@ class Server < ApplicationRecord
}
end
# Return the domain which can be used to authenticate emails sent from the given e-mail address.
#
#  @param address [String] an e-mail address
# @return [Domain, nil] the domain to use for authentication
def authenticated_domain_for_address(address)
return nil if address.blank?
@@ -226,16 +232,24 @@ class Server < ApplicationRecord
return nil unless uname
return nil unless domain_name
uname, = uname.split("+", 2)
# Find a verified domain which directly matches the domain name for the given address.
domain = Domain.verified
.order(owner_type: :desc)
.where("(owner_type = 'Organization' AND owner_id = ?) OR " \
"(owner_type = 'Server' AND owner_id = ?)", organization_id, id)
.where(name: domain_name)
.first
# Check the server's domain
if domain = Domain.verified.order(owner_type: :desc).where("(owner_type = 'Organization' AND owner_id = ?) OR (owner_type = 'Server' AND owner_id = ?)", organization_id, id).where(name: domain_name).first
return domain
end
# If there is a matching domain, return it
return domain if domain
return unless any_domain = domains.verified.where(use_for_any: true).order(:name).first
# Otherwise, we need to look to see if there is a domain configured which can be used as the authenticated
# domain for any domain. This will look for domains directly within the server and return that.
any_domain = domains.verified.where(use_for_any: true).order(:name).first
return any_domain if any_domain
any_domain
# Return nil if we can't find anything suitable
nil
end
def find_authenticated_domain_from_headers(headers)

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: smtp_endpoints
@@ -24,7 +26,7 @@ class SMTPEndpoint < ApplicationRecord
has_many :routes, as: :endpoint
has_many :additional_route_endpoints, dependent: :destroy, as: :endpoint
SSL_MODES = ["None", "Auto", "STARTTLS", "TLS"]
SSL_MODES = %w[None Auto STARTTLS TLS].freeze
before_destroy :update_routes

عرض الملف

@@ -1,11 +1,13 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: statistics
#
# id :integer not null, primary key
# total_messages :bigint(8) default(0)
# total_outgoing :bigint(8) default(0)
# total_incoming :bigint(8) default(0)
# total_incoming :bigint default(0)
# total_messages :bigint default(0)
# total_outgoing :bigint default(0)
#
class Statistic < ApplicationRecord

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: track_domains

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: users

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: user_invites

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: webhooks

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: webhook_events
@@ -14,16 +16,16 @@
class WebhookEvent < ApplicationRecord
EVENTS = [
"MessageSent",
"MessageDelayed",
"MessageDeliveryFailed",
"MessageHeld",
"MessageBounced",
"MessageLinkClicked",
"MessageLoaded",
"DomainDNSError"
]
EVENTS = %w[
MessageSent
MessageDelayed
MessageDeliveryFailed
MessageHeld
MessageBounced
MessageLinkClicked
MessageLoaded
DomainDNSError
].freeze
belongs_to :webhook

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: webhook_requests
@@ -19,7 +21,7 @@ class WebhookRequest < ApplicationRecord
include HasUUID
RETRIES = { 1 => 2.minutes, 2 => 3.minutes, 3 => 6.minutes, 4 => 10.minutes, 5 => 15.minutes }
RETRIES = { 1 => 2.minutes, 2 => 3.minutes, 3 => 6.minutes, 4 => 10.minutes, 5 => 15.minutes }.freeze
belongs_to :server
belongs_to :webhook, optional: true

عرض الملف

@@ -19,7 +19,11 @@
.fieldSet__input
= f.select :allow_sender, [["No", false], ["Yes - can use Sender header", true]], {}, :class => 'input input--select'
%p.fieldSet__text If enabled, outgoing messages can use any address in the From header as long as a Sender header is included with an authorized address.
.fieldSet__field
= f.label :privacy_mode, "Privacy mode", :class => 'fieldSet__label'
.fieldSet__input
= f.select :privacy_mode, [["Disabled", false], ["Enabled", true]], {}, :class => 'input input--select'
%p.fieldSet__text If enabled, when Postal adds Received headers to e-mails it will not include IP or hostname information of the client submitting the message.
.fieldSet__field
= f.label :log_smtp_data, "Log SMTP data?", :class => 'fieldSet__label'
.fieldSet__input

عرض الملف

@@ -1,4 +1,6 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
APP_PATH = File.expand_path("../config/application", __dir__)
require_relative "../config/boot"
require "rails/commands"

عرض الملف

@@ -1,4 +1,6 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require_relative "../config/boot"
require "rake"
Rake.application.run

عرض الملف

@@ -1,4 +1,6 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require "pathname"
require "fileutils"
include FileUtils

عرض الملف

@@ -1,4 +1,6 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require "pathname"
require "fileutils"
include FileUtils

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# This file is used by Rack-based servers to start the application.
require_relative "config/environment"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require_relative "boot"
require "rails"
@@ -30,7 +32,7 @@ module Postal
config.eager_load_paths << Rails.root.join("lib")
# Disable field_with_errors
config.action_view.field_error_proc = proc { |t, i| t }
config.action_view.field_error_proc = proc { |t, _| t }
# Load the tracking server middleware
require "postal/tracking_middleware"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
$stdout.sync = true

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Clockwork
configure do |config|

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# Load the Rails application.
require_relative "application"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
@@ -71,7 +73,7 @@ Rails.application.configure do
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger = ActiveSupport::Logger.new($stdout)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.

عرض الملف

@@ -1,3 +1,4 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# ApplicationController.renderer.defaults.merge!(

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets.

عرض الملف

@@ -1,3 +1,4 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Specify a serializer for the signed and encrypted cookie jars.

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Add new inflection rules using the following format. Inflections
@@ -12,7 +14,6 @@
# These inflection rules are supported but not enabled by default:
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym "DKIM"
inflect.acronym "HTTP"
inflect.acronym "SMTP"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require "mail"
module Mail
@@ -20,7 +22,7 @@ module Mail
## Extract plain text body of message
def plain_body
if multipart? and text_part
if multipart? && text_part
text_part.decoded
elsif mime_type == "text/plain" || mime_type.nil?
decoded
@@ -29,7 +31,7 @@ module Mail
## Extract HTML text body of message
def html_body
if multipart? and html_part
if multipart? && html_part
html_part.decoded
elsif mime_type == "text/html"
decoded
@@ -109,14 +111,16 @@ module Mail
# Handle attached emails as attachments
class AttachmentsList < Array
# rubocop:disable Lint/MissingSuper
def initialize(parts_list)
@parts_list = parts_list
@content_disposition_type = "attachment"
parts_list.map do |p|
(p.parts.empty? and p.attachment?) ? p : p.attachments
end.flatten.compact.each { |a| self << a }
self
parts = parts_list.map do |p|
p.parts.empty? && p.attachment? ? p : p.attachments
end.flatten.compact
parts.each { |a| self << a }
end
# rubocop:enable Lint/MissingSuper
end

لم تُعرض بعض الملفات لأن الكثير من الملفات تغيرت في هذا الاختلاف إظهار المزيد