diff --git a/flake.lock b/flake.lock index 123d63e..8cb1fc0 100644 --- a/flake.lock +++ b/flake.lock @@ -373,11 +373,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1741352980, - "narHash": "sha256-+u2UunDA4Cl5Fci3m7S643HzKmIDAe+fiXrLqYsR2fs=", + "lastModified": 1743550720, + "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "f4330d22f1c5d2ba72d3d22df5597d123fdb60a9", + "rev": "c621e8422220273271f52058f618c94e405bb0f5", "type": "github" }, "original": { @@ -625,11 +625,11 @@ }, "nixpkgs-lib": { "locked": { - "lastModified": 1740877520, - "narHash": "sha256-oiwv/ZK/2FhGxrCkQkB83i7GnWXPPLzoqFHpDD3uYpk=", + "lastModified": 1743296961, + "narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=", "owner": "nix-community", "repo": "nixpkgs.lib", - "rev": "147dee35aab2193b174e4c0868bd80ead5ce755c", + "rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa", "type": "github" }, "original": { @@ -698,11 +698,11 @@ }, "nixpkgs_6": { "locked": { - "lastModified": 1742889210, - "narHash": "sha256-hw63HnwnqU3ZQfsMclLhMvOezpM7RSB0dMAtD5/sOiw=", + "lastModified": 1743827369, + "narHash": "sha256-rpqepOZ8Eo1zg+KJeWoq1HAOgoMCDloqv5r2EAa9TSA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "698214a32beb4f4c8e3942372c694f40848b360d", + "rev": "42a1c966be226125b48c384171c44c651c236c22", "type": "github" }, "original": { @@ -849,11 +849,11 @@ ] }, "locked": { - "lastModified": 1742700801, - "narHash": "sha256-ZGlpUDsuBdeZeTNgoMv+aw0ByXT2J3wkYw9kJwkAS4M=", + "lastModified": 1743910657, + "narHash": "sha256-zr2jmWeWyhCD8WmO2aWov2g0WPPuZfcJDKzMJZYGq3Y=", "owner": "Mic92", "repo": "sops-nix", - "rev": "67566fe68a8bed2a7b1175fdfb0697ed22ae8852", + "rev": "523f58a4faff6c67f5f685bed33a7721e984c304", "type": "github" }, "original": { diff --git a/packages/alias-to-sieve/Cargo.lock b/packages/alias-to-sieve/Cargo.lock index dcf9e88..f7dffe3 100644 --- a/packages/alias-to-sieve/Cargo.lock +++ b/packages/alias-to-sieve/Cargo.lock @@ -119,9 +119,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "once_cell" -version = "1.21.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2806eaa3524762875e21c3dcd057bc4b7bfa01ce4da8d46be1cd43649e1cc6b" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "pest" diff --git a/packages/alias-to-sieve/Cargo.toml b/packages/alias-to-sieve/Cargo.toml index 77b7e28..488dab9 100644 --- a/packages/alias-to-sieve/Cargo.toml +++ b/packages/alias-to-sieve/Cargo.toml @@ -4,6 +4,10 @@ version = "0.1.0" edition = "2021" rust-version = "1.68.2" +description = "Convert an alias file to a sieve script for stalwart-mail" +readme = "README.md" +license = " AGPL-3.0-only" +keywords = ["mail", "sieve", "alias", "stalwart"] [dependencies] fqdn = {version = "0.4.2", features = ["domain-label-length-limited-to-63", "domain-name-without-special-chars"]} diff --git a/packages/alias-to-sieve/README.md b/packages/alias-to-sieve/README.md new file mode 100644 index 0000000..339219c --- /dev/null +++ b/packages/alias-to-sieve/README.md @@ -0,0 +1,60 @@ +This script converts an alias file to a sieve script for [stalwart-mail](https://stalw.art/). + +## Usage +Given an alias file `testdata/simple.aliases` that contains lines of redirects of the form localpart with optional `@fqdn` followed by a space followed by a list (space or comma+space separated) list of destinations that consist of a localpart and optionally an `@fqdn`. +If you don't define a fqdn along any of the addresses, the default domain from your commandline input will be appended. + +An example using the testdata directory of this repository: +``` +$ ./alias_to_sieve testdata/simple.aliases example.com +require ["variables", "copy", "vnd.stalwart.expressions", "envelope", "editheader"]; + +let "i" "0"; +while "i < count(envelope.to)" { + let "redirected" "false"; + if eval "eq_ignore_case(envelope.to[i], 'admin@example.com')" { + addheader "Delivered-To" "admin@example.com"; + redirect :copy "me@example.org"; + + deleteheader :index 1 :is "Delivered-To" "admin@example.com"; + let "redirected" "true"; + } + if eval "eq_ignore_case(envelope.to[i], 'postmaster@example.com')" { + addheader "Delivered-To" "postmaster@example.com"; + redirect :copy "me@example.org"; + + deleteheader :index 1 :is "Delivered-To" "postmaster@example.com"; + let "redirected" "true"; + } + if eval "eq_ignore_case(envelope.to[i], 'root@example.com')" { + addheader "Delivered-To" "root@example.com"; + redirect :copy "me@example.org"; + + deleteheader :index 1 :is "Delivered-To" "root@example.com"; + let "redirected" "true"; + } + if eval "eq_ignore_case(envelope.to[i], 'sudo@example.com')" { + addheader "Delivered-To" "sudo@example.com"; + redirect :copy "me@example.org"; + + deleteheader :index 1 :is "Delivered-To" "sudo@example.com"; + let "redirected" "true"; + } + if eval "!redirected" { + let "destination" "envelope.to[i]"; + redirect :copy "${destination}"; + } + let "i" "i+1"; +} +discard; + +``` + +## Limitations +You cannot use apostrophes (') in any mail addresses although allowed by [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322) since they would break termination of strings in sieve. + +This parser is not designed with security in mind. While the above gives some basic protection against code injection, I have no idea whether sieve has other pitfalls that might allow them. + +This is my first rust project, consume the code with care. + +The generated code is specific to stalwart-mail and contains non-standard sieve features.