-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ed7664a
Showing
17 changed files
with
1,161 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
name: publish | ||
|
||
on: | ||
push: | ||
branches: [ 'master' ] | ||
|
||
jobs: | ||
publish: | ||
name: publish | ||
permissions: write-all | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/setup-go@v4 | ||
with: | ||
go-version: '1.21' | ||
- uses: actions/checkout@v3 | ||
- uses: ko-build/setup-ko@v0.6 | ||
- run: ko build --platform=linux/amd64 --bare |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.env | ||
.idea | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
ifneq (,$(wildcard ./.env)) | ||
include .env | ||
export | ||
endif | ||
|
||
run: | ||
@go run main.go | ||
|
||
integration: | ||
@go test -v ./... -tags=integration | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
### Erida: Simplifying Internal Cluster Communication | ||
|
||
**Erida** is a straightforward SMTP relay server designed for sending internal cluster emails to an authenticated SMTP | ||
server with seamless Slack integration. | ||
|
||
### Email Address Flexibility | ||
|
||
Erida supports a variety of email addresses, including common ones like `avfadeev@gmail.com` and those associated with | ||
messaging services, particularly Slack. | ||
|
||
For Slack integration, you can use addresses following this syntax: | ||
|
||
- User-specific Slack address: `personal.<username>@slack` | ||
- Channel-specific Slack address: `channel.<channelname>@slack` | ||
|
||
It's important to note that both the `username` and `channelname` are case-insensitive, and the bot must have the | ||
necessary | ||
permissions to access the specified Slack channels. | ||
|
||
### Configuration Made Easy | ||
|
||
Configuring Erida is a breeze. All you need to do is set the following environment variables: | ||
|
||
- `SMTP_HOST`: SMTP server host | ||
- `SMTP_PORT`: SMTP server port | ||
- `SMTP_USER`: SMTP server username | ||
- `SMTP_PASSWORD`: SMTP server password | ||
- `SLACK_TOKEN`: Slack bot token | ||
- `SMTP_TLS` (Optional, default: true): Enable or disable Start TLS usage | ||
|
||
For additional variables, refer to the [configuration file](internal/config.go). | ||
|
||
### Getting Started | ||
|
||
If you're new to configuring the bot, check out the step-by-step guide | ||
at [Slack Quickstart](https://api.slack.com/start/quickstart). | ||
|
||
Ensure that the bot has the necessary permissions, specifically `chat:write`. | ||
|
||
### Example Usage | ||
|
||
Let's walk through an example. Assume that an external SMTP server is configured to send emails to **Erida** with the | ||
following addresses: `personal.fadyat@slack`, `channel.general@slack`, and `avfadeev@gmail.com`. | ||
|
||
The message will be seamlessly delivered to the Slack channel `#general` and the Slack user `@fadyat`, as well as to the | ||
email address `avfadeev@gmail.com`. | ||
|
||
**Erida** simplifies internal communication, bridging the gap between email and Slack effortlessly. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
module github.com/fadyat/erida | ||
|
||
go 1.21 | ||
|
||
require ( | ||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 | ||
github.com/emersion/go-smtp v0.19.0 | ||
github.com/ilyakaznacheev/cleanenv v1.5.0 | ||
github.com/mocktools/go-smtp-mock/v2 v2.1.0 | ||
github.com/slack-go/slack v0.12.3 | ||
github.com/stretchr/testify v1.8.4 | ||
) | ||
|
||
require ( | ||
github.com/BurntSushi/toml v1.3.2 // indirect | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/gorilla/websocket v1.5.1 // indirect | ||
github.com/joho/godotenv v1.5.1 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
github.com/stretchr/objx v0.5.0 // indirect | ||
golang.org/x/net v0.18.0 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= | ||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= | ||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ= | ||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ= | ||
github.com/emersion/go-smtp v0.19.0 h1:iVCDtR2/JY3RpKoaZ7u6I/sb52S3EzfNHO1fAWVHgng= | ||
github.com/emersion/go-smtp v0.19.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ= | ||
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= | ||
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= | ||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= | ||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= | ||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | ||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= | ||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= | ||
github.com/ilyakaznacheev/cleanenv v1.5.0 h1:0VNZXggJE2OYdXE87bfSSwGxeiGt9moSR2lOrsHHvr4= | ||
github.com/ilyakaznacheev/cleanenv v1.5.0/go.mod h1:a5aDzaJrLCQZsazHol1w8InnDcOX0OColm64SlIi6gk= | ||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= | ||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= | ||
github.com/mocktools/go-smtp-mock/v2 v2.1.0 h1:gGiWqlaMTExk7Id38G2+sWfOelsE+OAqJWAMsAI/654= | ||
github.com/mocktools/go-smtp-mock/v2 v2.1.0/go.mod h1:n8aNpDYncZHH/cZHtJKzQyeYT/Dut00RghVM+J1Ed94= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/slack-go/slack v0.12.3 h1:92/dfFU8Q5XP6Wp5rr5/T5JHLM5c5Smtn53fhToAP88= | ||
github.com/slack-go/slack v0.12.3/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= | ||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= | ||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= | ||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 h1:slmdOY3vp8a7KQbHkL+FLbvbkgMqmXojpFUO/jENuqQ= | ||
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3/go.mod h1:oVgVk4OWVDi43qWBEyGhXgYxt7+ED4iYNpTngSLX2Iw= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package internal | ||
|
||
import ( | ||
"fmt" | ||
"github.com/slack-go/slack" | ||
"strings" | ||
) | ||
|
||
const ( | ||
emailRecipient = "email" | ||
slackRecipient = "slack" | ||
|
||
personalMessage = "personal." | ||
channelMessage = "channel." | ||
) | ||
|
||
var ( | ||
operators = map[string]map[string]string{ | ||
slackRecipient: { | ||
personalMessage: "@", | ||
channelMessage: "#", | ||
}, | ||
} | ||
) | ||
|
||
type client interface { | ||
|
||
// proxify is a function, that will be used as a proxy for the data. | ||
proxify(from string, to []string, body string) error | ||
} | ||
|
||
func takeUsernames(recipients []string, recipientType string) []string { | ||
var usernames = make([]string, 0, len(recipients)) | ||
|
||
for _, r := range recipients { | ||
at := strings.Split(r, "@") | ||
if len(at) != 2 { | ||
continue | ||
} | ||
|
||
if at[1] != recipientType { | ||
continue | ||
} | ||
|
||
usernames = append(usernames, convertToRecipientWay(at[0], recipientType)) | ||
} | ||
|
||
return usernames | ||
} | ||
|
||
func convertToRecipientWay(username string, recipientType string) string { | ||
if _, ok := operators[recipientType]; !ok { | ||
return username | ||
} | ||
|
||
var msgType string | ||
switch { | ||
case strings.HasPrefix(username, personalMessage): | ||
msgType = personalMessage | ||
case strings.HasPrefix(username, channelMessage): | ||
msgType = channelMessage | ||
} | ||
|
||
operator := operators[recipientType][msgType] | ||
return operator + strings.TrimPrefix(username, msgType) | ||
} | ||
|
||
func selectClientType(recipient string) (string, error) { | ||
at := strings.Split(recipient, "@") | ||
if len(at) != 2 { | ||
return "", fmt.Errorf("invalid recipient: %s", recipient) | ||
} | ||
|
||
domain := at[1] | ||
if domain == slackRecipient { | ||
return slackRecipient, nil | ||
} | ||
|
||
return emailRecipient, nil | ||
} | ||
|
||
func selectClient(clientType string, cfg *Config) (client, error) { | ||
switch clientType { | ||
case emailRecipient: | ||
return newMailClient(cfg) | ||
case slackRecipient: | ||
return newSlackClient(slack.New(cfg.SlackToken)), nil | ||
default: | ||
return nil, fmt.Errorf("unknown client type: %s", clientType) | ||
} | ||
} | ||
|
||
func groupByClientType(recipients []string) (map[string][]string, error) { | ||
groups := make(map[string][]string) | ||
|
||
for _, recipient := range recipients { | ||
clientType, err := selectClientType(recipient) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to select client type: %w", err) | ||
} | ||
|
||
groups[clientType] = append(groups[clientType], recipient) | ||
} | ||
|
||
return groups, nil | ||
} |
Oops, something went wrong.