From d3a672694ff06db1fd0fb1712b3cbdea62e35127 Mon Sep 17 00:00:00 2001 From: paspo Date: Tue, 4 Jun 2024 22:46:09 +0200 Subject: [PATCH] initial POC --- .gitignore | 3 + .vscode/launch.json | 20 +++++ cmd/server/main.go | 35 ++++++++ go.mod | 57 +++++++++++++ go.sum | 154 +++++++++++++++++++++++++++++++++ internal/app/app.go | 62 ++++++++++++++ internal/app/domain.go | 26 ++++++ internal/app/outlook.go | 135 +++++++++++++++++++++++++++++ internal/app/thunderbird.go | 90 ++++++++++++++++++++ internal/config/config.go | 35 ++++++++ internal/db/db.go | 155 ++++++++++++++++++++++++++++++++++ internal/myerrors/myerrors.go | 9 ++ 12 files changed, 781 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 cmd/server/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/app/app.go create mode 100644 internal/app/domain.go create mode 100644 internal/app/outlook.go create mode 100644 internal/app/thunderbird.go create mode 100644 internal/config/config.go create mode 100644 internal/db/db.go create mode 100644 internal/myerrors/myerrors.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..93235eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +**/__debug_bin* +/vendor/ +*.sqlite diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..520efac --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Run", + "type": "go", + "request": "launch", + "mode": "auto", + "env": { + "PORT": "8888", + "DB_PATH": "./db.sqlite", + }, + "cwd": "${workspaceFolder}", + "program": "cmd/server/main.go" + } + ] +} diff --git a/cmd/server/main.go b/cmd/server/main.go new file mode 100644 index 0000000..20243cf --- /dev/null +++ b/cmd/server/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "fmt" + + "git.asperti.com/paspo/mail-autoconfig/internal/app" + "git.asperti.com/paspo/mail-autoconfig/internal/config" + "git.asperti.com/paspo/mail-autoconfig/internal/db" +) + +// "github.com/sirupsen/logrus" +// "github.com/snykk/go-rest-boilerplate/cmd/api/server" +// "github.com/snykk/go-rest-boilerplate/internal/config" +// "github.com/snykk/go-rest-boilerplate/internal/constants" +// "github.com/snykk/go-rest-boilerplate/pkg/logger" + +func init() { + if err := config.InitConfig(); err != nil { + // logger.Fatal(err.Error(), logrus.Fields{constants.LoggerCategory: constants.LoggerCategoryConfig}) + fmt.Printf("ko config\n") + } + if err := db.InitDB(); err != nil { + // logger.Fatal(err.Error(), logrus.Fields{constants.LoggerCategory: constants.LoggerCategoryConfig}) + fmt.Printf("ko db\n") + } + +} + +func main() { + fmt.Printf("ciao\n") + if err := app.FetchAllDomains(); err != nil { + fmt.Printf("ko fetch\n") + } + app.Start() +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..bc036c5 --- /dev/null +++ b/go.mod @@ -0,0 +1,57 @@ +module git.asperti.com/paspo/mail-autoconfig + +go 1.22 + +require ( + github.com/gin-gonic/gin v1.10.0 + github.com/gookit/validate v1.5.2 + github.com/jmoiron/sqlx v1.4.0 + github.com/mattn/go-sqlite3 v1.14.22 + github.com/spf13/viper v1.19.0 +) + +require ( + github.com/bytedance/sonic v1.11.6 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.20.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/gookit/filter v1.2.1 // indirect + github.com/gookit/goutil v0.6.15 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..b564b2a --- /dev/null +++ b/go.sum @@ -0,0 +1,154 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= +github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= +github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gookit/filter v1.2.1 h1:37XivkBm2E5qe1KaGdJ5ZfF5l9NYdGWfLEeQadJD8O4= +github.com/gookit/filter v1.2.1/go.mod h1:rxynQFr793x+XDwnRmJFEb53zDw0Zqx3OD7TXWoR9mQ= +github.com/gookit/goutil v0.6.15 h1:mMQ0ElojNZoyPD0eVROk5QXJPh2uKR4g06slgPDF5Jo= +github.com/gookit/goutil v0.6.15/go.mod h1:qdKdYEHQdEtyH+4fNdQNZfJHhI0jUZzHxQVAV3DaMDY= +github.com/gookit/validate v1.5.2 h1:i5I2OQ7WYHFRPRATGu9QarR9snnNHydvwSuHXaRWAV0= +github.com/gookit/validate v1.5.2/go.mod h1:yuPy2WwDlwGRa06fFJ5XIO8QEwhRnTC2LmxmBa5SE14= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +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/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +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= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/app/app.go b/internal/app/app.go new file mode 100644 index 0000000..a621517 --- /dev/null +++ b/internal/app/app.go @@ -0,0 +1,62 @@ +package app + +import ( + "fmt" + "log" + + "text/template" + + "git.asperti.com/paspo/mail-autoconfig/internal/config" + "git.asperti.com/paspo/mail-autoconfig/internal/db" + "github.com/gin-gonic/gin" +) + +var Domains map[string]Domain +var Router *gin.Engine + +func init() { + var err error + Domains = make(map[string]Domain) + + thunderbirdTemplate, err = template.New("thunderbird").Parse(thunderbirdTpl) + if err != nil { + log.Fatal(err) // TODO + } + + outlookTemplate, err = template.New("outlook").Parse(outlookTpl) + if err != nil { + log.Fatal(err) // TODO + } + + Router = gin.Default() + Router.GET("/.well-known/autoconfig/mail/config-v1.1.xml", RenderThunderbird) + Router.GET("/mail/config-v1.1.xml", RenderThunderbird) + Router.POST("/autodiscover/autodiscover.xml", RenderOutlook) +} + +func FetchAllDomains() error { + var err error + rows, err := db.DB.Queryx("select * from domains") + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var d Domain + err := rows.StructScan(&d) + if err != nil { + return err + } + Domains[d.Domain] = d + } + err = rows.Err() + if err != nil { + return err + } + return nil +} + +func Start() { + address := fmt.Sprintf(":%d", config.AppConfig.HttpPort) + Router.Run(address) +} diff --git a/internal/app/domain.go b/internal/app/domain.go new file mode 100644 index 0000000..506bf11 --- /dev/null +++ b/internal/app/domain.go @@ -0,0 +1,26 @@ +package app + +type Domain struct { + Domain string `db:"domain"` + DisplayName string `db:"display_name"` + DisplayShortName string `db:"display_shortname"` + IMAPEnabled bool `db:"imap_enabled"` + IMAPServer string `db:"imap_server"` + IMAPPort int `db:"imap_port"` + IMAPSSL bool `db:"imap_ssl"` + IMAPSPA bool `db:"imap_spa"` + POP3Enabled bool `db:"pop3_enabled"` + POP3Server string `db:"pop3_server"` + POP3Port int `db:"pop3_port"` + POP3SSL bool `db:"pop3_ssl"` + POP3SPA bool `db:"pop3_spa"` + SMTPEnabled bool `db:"smtp_enabled"` + SMTPServer string `db:"smtp_server"` + SMTPPort int `db:"smtp_port"` + SMTPSSL bool `db:"smtp_ssl"` + SMTPTLS bool `db:"smtp_tls"` + SMTPSPA bool `db:"smtp_spa"` + POPBeforeSMTP bool `db:"pop_before_smtp"` + DomainRequired bool `db:"domain_required"` + Username string +} diff --git a/internal/app/outlook.go b/internal/app/outlook.go new file mode 100644 index 0000000..0af4e01 --- /dev/null +++ b/internal/app/outlook.go @@ -0,0 +1,135 @@ +package app + +import ( + "bytes" + "encoding/xml" + "io" + "log" + "net/http" + "strings" + "text/template" + + "github.com/gin-gonic/gin" +) + +const outlookTpl = ` + + + + email + settings + +{{- if .IMAPEnabled }} + + IMAP + {{ .IMAPServer }} + {{ .IMAPPort }} + on + off + {{ if .IMAPSSL }}on{{ else }}off{{ end }} + on + {{ .Username }}@{{ .Domain }} + +{{- end }} + +{{- if .POP3Enabled }} + + POP3 + mail.mdfmultimedia.com + 995 + on + off + {{ if .POP3SSL }}on{{ else }}off{{ end }} + on + {{ .Username }}@{{ .Domain }} + +{{- end }} + +{{- if .SMTPEnabled }} + + SMTP + mail.mdfmultimedia.com + 465 + on + off + {{ if .SMTPSSL }}on{{ else }}off{{ end }} + on + {{ .Username }}@{{ .Domain }} + +{{- end }} + + + + +` + +var outlookTemplate *template.Template + +func RenderOutlook(g *gin.Context) { + var err error + var body []byte + var domain Domain + var ok bool + var b bytes.Buffer + + body, err = io.ReadAll(g.Request.Body) + if err != nil { + g.JSON(404, gin.H{"code": "WRONG_BODY", "message": "malformed request"}) + return + } + + var e struct { + Address string `xml:"Request>EMailAddress"` + } + + err = xml.Unmarshal(body, &e) + if err != nil { + g.JSON(404, gin.H{"code": "PAGE_NOT_FOUND", "message": "Page not found"}) + return + } + + components := strings.Split(e.Address, "@") + username, reqDomain := components[0], components[1] + + domain, ok = Domains[reqDomain] + if !ok { + g.JSON(404, gin.H{"code": "PAGE_NOT_FOUND", "message": "Page not found"}) + return + } + + domain.Username = username + err = outlookTemplate.Execute(&b, domain) + if err != nil { + log.Fatal(err) + } + + g.Header("Content-Type", "application/xml; charset=utf-8") + g.String(http.StatusOK, b.String()) +} + +// curl -X POST -d @req.xml http://127.0.0.1:8888/autodiscover/autodiscover.xml +// curl --basic -X "POST" -u XXX@YYY -v https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml -H "Content-Type: text/xml" -d @a.txt + +/* + + + + testuser@company.tld + + http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006 + + + + +$ curl -d @request.xml -u testuser@company.tld -H "Content-Type: text/xml" -v https://autodiscover.company.tld/autodiscover/autodiscover.xml + +*/ + +/* + + 1 - Lookup di un record A (o CNAME) per contoso.com che punta ad un web server che risponderà con un URL HTTPS https://contoso.com/Autodiscover/Autodiscover.xml. + 2 - Lookup di un record A (o CNAME) per autodiscover.contoso.com che punta ad un web server che risponderà con un URL HTTPS https://autodiscover.contoso.com/Autodiscover/Autodiscover.xml + 3 - Lookup di un record A (o CNAME) per contoso.com che punta ad un web server che risponderà con URL HTTP http://autodiscover.contoso.com/Autodiscover/Autodiscover.xml (se avete un reverse proxy o direttamente su Exchange, dovrete fare la configurazione necessaria per implementare l’http to https redirect) + 4 - Lookup di un record SRV per autodiscover._tcp.contoso.com (Questo record deve contenere la porta 443 e l’hostname, ad esempio mail.contoso.com, permetendo cosi al client di fare una request in https all’URL https://mail.contoso.com/Autodiscover/Autodiscover.xml) + +*/ diff --git a/internal/app/thunderbird.go b/internal/app/thunderbird.go new file mode 100644 index 0000000..5304b80 --- /dev/null +++ b/internal/app/thunderbird.go @@ -0,0 +1,90 @@ +package app + +import ( + "bytes" + "log" + "net/http" + "text/template" + + "github.com/gin-gonic/gin" +) + +const thunderbirdTpl = ` + + +{{ .Domain }} +{{ .DisplayName }} +{{ .DisplayShortName }} + +{{- if .IMAPEnabled }} + +{{ .IMAPServer }} +{{ .IMAPPort }} +{{- if .IMAPSSL }} +SSL +{{- else }} +plain +{{- end }} +password-encrypted +%EMAILADDRESS% + +{{- end }} + +{{- if .POP3Enabled }} + +{{ .POP3Server }} +{{ .POP3Port }} +{{- if .POP3SSL }} +SSL +{{- else }} +plain +{{- end }} +password-cleartext +%EMAILADDRESS% + +{{- end }} + +{{- if .SMTPEnabled }} + +{{ .SMTPServer }} +{{ .SMTPPort }} +{{- if .SMTPSSL }} +SSL +{{- else }} +{{if .SMTPTLS }} +STARTTLS +{{- else }} +plain +{{- end }} +{{- end }} +password-encrypted +%EMAILADDRESS% + +{{- end }} + + + +` + +var thunderbirdTemplate *template.Template + +// https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat + +func RenderThunderbird(g *gin.Context) { + host := g.Request.Host + domain, ok := Domains[host] + if !ok { + g.JSON(404, gin.H{"code": "PAGE_NOT_FOUND", "message": "Page not found"}) + return + } + + var b bytes.Buffer + if err := thunderbirdTemplate.Execute(&b, domain); err != nil { + log.Fatal(err) + } + + g.Header("Content-Type", "application/xml; charset=utf-8") + g.String(http.StatusOK, b.String()) +} + +// curl http://127.0.0.1:8888/.well-known/autoconfig/mail/config-v1.1.xml diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..c6b92b1 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,35 @@ +package config + +import ( + "git.asperti.com/paspo/mail-autoconfig/internal/myerrors" + "github.com/gookit/validate" + "github.com/spf13/viper" +) + +type Config struct { + HttpPort int `mapstructure:"PORT" validate:"required|int|min:1|max:65535"` + DBPath string `mapstructure:"DB_PATH" validate:"required"` +} + +var AppConfig Config + +func InitConfig() error { + var err error + viper.SetConfigType("env") + viper.AllowEmptyEnv(true) + viper.AutomaticEnv() + + viper.SetDefault("PORT", 9000) + viper.SetDefault("DB_PATH", "./database.sqlite") + + err = viper.Unmarshal(&AppConfig) + if err != nil { + return myerrors.ErrConfigParse + } + + validation := validate.Struct(AppConfig) + if !validation.Validate() { + return myerrors.ErrConfigValidation + } + return nil +} diff --git a/internal/db/db.go b/internal/db/db.go new file mode 100644 index 0000000..5710716 --- /dev/null +++ b/internal/db/db.go @@ -0,0 +1,155 @@ +package db + +import ( + "fmt" + "log" + + "git.asperti.com/paspo/mail-autoconfig/internal/config" + "github.com/jmoiron/sqlx" + _ "github.com/mattn/go-sqlite3" +) + +var ( + dbStructure []string +) + +var DB *sqlx.DB + +func init() { + dbStructure = []string{ + `CREATE TABLE IF NOT EXISTS domains ( + domain VARCHAR PRIMARY KEY, + display_name VARCHAR, + display_shortname VARCHAR, + imap_enabled BOOL, + imap_server VARCHAR, + imap_port INT, + imap_ssl BOOL, + imap_spa BOOL, + pop3_enabled BOOL, + pop3_server VARCHAR, + pop3_port INT, + pop3_ssl BOOL, + pop3_spa BOOL, + smtp_enabled BOOL, + smtp_server VARCHAR, + smtp_port INT, + smtp_ssl BOOL, + smtp_tls BOOL, + smtp_spa BOOL, + pop_before_smtp BOOL, + domain_required BOOL);`, + } +} + +func InitDB() error { + var err error + + DB, err = sqlx.Open("sqlite3", config.AppConfig.DBPath) + if err != nil { + return err + } + + for _, stmt := range dbStructure { + _, err = DB.Exec(stmt) + if err != nil { + return err + } + } + + return nil +} + +func DoiooooDELME() { + var err error + sqlStmt := ` + create table foo (id integer not null primary key, name text); + delete from foo; + ` + _, err = DB.Exec(sqlStmt) + if err != nil { + log.Printf("%q: %s\n", err, sqlStmt) + return + } + + tx, err := DB.Begin() + if err != nil { + log.Fatal(err) + } + stmt, err := tx.Prepare("insert into foo(id, name) values(?, ?)") + if err != nil { + log.Fatal(err) + } + defer stmt.Close() + for i := 0; i < 100; i++ { + _, err = stmt.Exec(i, fmt.Sprintf("こんにちは世界%03d", i)) + if err != nil { + log.Fatal(err) + } + } + err = tx.Commit() + if err != nil { + log.Fatal(err) + } + + rows, err := DB.Query("select id, name from foo") + if err != nil { + log.Fatal(err) + } + defer rows.Close() + for rows.Next() { + var id int + var name string + err = rows.Scan(&id, &name) + if err != nil { + log.Fatal(err) + } + fmt.Println(id, name) + } + err = rows.Err() + if err != nil { + log.Fatal(err) + } + + stmt, err = DB.Prepare("select name from foo where id = ?") + if err != nil { + log.Fatal(err) + } + defer stmt.Close() + var name string + err = stmt.QueryRow("3").Scan(&name) + if err != nil { + log.Fatal(err) + } + fmt.Println(name) + + _, err = DB.Exec("delete from foo") + if err != nil { + log.Fatal(err) + } + + _, err = DB.Exec("insert into foo(id, name) values(1, 'foo'), (2, 'bar'), (3, 'baz')") + if err != nil { + log.Fatal(err) + } + + rows, err = DB.Query("select id, name from foo") + if err != nil { + log.Fatal(err) + } + defer rows.Close() + for rows.Next() { + var id int + var name string + err = rows.Scan(&id, &name) + if err != nil { + log.Fatal(err) + } + fmt.Println(id, name) + } + err = rows.Err() + if err != nil { + log.Fatal(err) + } + +} diff --git a/internal/myerrors/myerrors.go b/internal/myerrors/myerrors.go new file mode 100644 index 0000000..b105d59 --- /dev/null +++ b/internal/myerrors/myerrors.go @@ -0,0 +1,9 @@ +package myerrors + +import "errors" + +var ( + // ErrConfigLoad = errors.New("Failed to load configuration") + ErrConfigParse = errors.New("Failed to parse configuration") + ErrConfigValidation = errors.New("Failed to validate configuration") +)