diff --git a/api/openapi.yaml b/api/openapi.yaml index 23a189f..8463007 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -942,10 +942,6 @@ components: $ref: '#/components/schemas/DMARCRecord' bimi_record: $ref: '#/components/schemas/BIMIRecord' - dnssec_enabled: - type: boolean - description: Whether the From domain has DNSSEC enabled with valid chain of trust - example: true ptr_records: type: array items: diff --git a/go.mod b/go.mod index 85be917..5cef1e4 100644 --- a/go.mod +++ b/go.mod @@ -5,33 +5,31 @@ go 1.24.6 require ( github.com/JGLTechnologies/gin-rate-limit v1.5.6 github.com/emersion/go-smtp v0.24.0 - github.com/getkin/kin-openapi v0.133.0 github.com/gin-gonic/gin v1.11.0 github.com/google/uuid v1.6.0 github.com/oapi-codegen/runtime v1.1.2 golang.org/x/net v0.47.0 gorm.io/driver/postgres v1.6.0 gorm.io/driver/sqlite v1.6.0 - gorm.io/gorm v1.31.1 + gorm.io/gorm v1.31.0 ) require ( - github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect - github.com/bytedance/gopkg v0.1.3 // indirect - github.com/bytedance/sonic v1.14.2 // indirect - github.com/bytedance/sonic/loader v0.4.0 // indirect + github.com/bytedance/sonic v1.14.0 // indirect + github.com/bytedance/sonic/loader v0.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 // indirect - github.com/gabriel-vasile/mimetype v1.4.11 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/getkin/kin-openapi v0.133.0 // indirect github.com/gin-contrib/sse v1.1.0 // indirect - github.com/go-openapi/jsonpointer v0.22.2 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/swag v0.23.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.28.0 // indirect + github.com/go-playground/validator/v10 v10.27.0 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-yaml v1.18.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -44,10 +42,9 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/mailru/easyjson v0.9.1 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.32 // indirect - github.com/miekg/dns v1.1.4 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect @@ -56,25 +53,24 @@ require ( github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/peterzen/goresolver v1.0.2 // indirect github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.56.0 // indirect - github.com/redis/go-redis/v9 v9.16.0 // indirect + github.com/quic-go/quic-go v0.54.1 // indirect + github.com/redis/go-redis/v9 v9.7.3 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.3.1 // indirect + github.com/ugorji/go/codec v1.3.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.4.0 // indirect - go.uber.org/mock v0.6.0 // indirect - golang.org/x/arch v0.23.0 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect + go.uber.org/mock v0.5.0 // indirect + golang.org/x/arch v0.20.0 // indirect golang.org/x/crypto v0.44.0 // indirect - golang.org/x/mod v0.30.0 // indirect + golang.org/x/mod v0.29.0 // indirect golang.org/x/sync v0.18.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect - golang.org/x/tools v0.39.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + golang.org/x/tools v0.38.0 // indirect + google.golang.org/protobuf v1.36.9 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 825604f..1def6c0 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +1,13 @@ github.com/JGLTechnologies/gin-rate-limit v1.5.6 h1:BrL2wXrF7SSqmB88YTGFVKMGVcjURMUeKqwQrlmzweI= github.com/JGLTechnologies/gin-rate-limit v1.5.6/go.mod h1:fwUuBegxLKm8+/4ST0zDFssRFTFaVZ7bH3ApK7iNZww= -github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= -github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= -github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= -github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= -github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= -github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= -github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE= -github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980= -github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o= -github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= +github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= +github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= +github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= +github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -36,28 +30,26 @@ github.com/emersion/go-smtp v0.24.0/go.mod h1:ZtRRkbTyp2XTHCA+BmyTFTrj8xY4I+b4Mc github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik= -github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls= -github.com/go-openapi/jsonpointer v0.22.2 h1:JDQEe4B9j6K3tQ7HQQTZfjR59IURhjjLxet2FB4KHyg= -github.com/go-openapi/jsonpointer v0.22.2/go.mod h1:0lBbqeRsQ5lIanv3LHZBrmRGHLHcQoOXQnf88fHlGWo= -github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU= -github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= 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.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688= -github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU= +github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= +github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= @@ -102,7 +94,6 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 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/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -114,14 +105,12 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= -github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 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.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/miekg/dns v1.1.4 h1:rCMZsU2ScVSYcAsOXgmC6+AKOK+6pmQTOcw03nfwYV0= -github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 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= @@ -156,16 +145,14 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0 github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/peterzen/goresolver v1.0.2 h1:UxRxk835Onz7Go4oPUsOptSmBlIvN/yJ2kv3Srr3hw4= -github.com/peterzen/goresolver v1.0.2/go.mod h1:LrWRiOeCYApgvR2OhpipNOeaE1yGfI+QQjpF0riJC8M= 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/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.56.0 h1:q/TW+OLismmXAehgFLczhCDTYB3bFmua4D9lsNBWxvY= -github.com/quic-go/quic-go v0.56.0/go.mod h1:9gx5KsFQtw2oZ6GZTyh+7YEvOxWCL9WZAepnHxgAo6c= -github.com/redis/go-redis/v9 v9.16.0 h1:OotgqgLSRCmzfqChbQyG1PHC3tLNR89DG4jdOERSEP4= -github.com/redis/go-redis/v9 v9.16.0/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= +github.com/quic-go/quic-go v0.54.1 h1:4ZAWm0AhCb6+hE+l5Q1NAL0iRn/ZrMwqHRGQiFwj2eg= +github.com/quic-go/quic-go v0.54.1/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= +github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= +github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= @@ -174,45 +161,40 @@ github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= -github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= 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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 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.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= -github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= +github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= -github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= -github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= +github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= -go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= -golang.org/x/arch v0.23.0 h1:lKF64A2jF6Zd8L0knGltUnegD62JMFBiCPBmQpToHhg= -golang.org/x/arch v0.23.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= -golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= +golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -222,14 +204,12 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222171317-cd391775e71e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -253,13 +233,11 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -272,8 +250,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -295,5 +273,5 @@ gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4= gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo= gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= -gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= -gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= +gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY= +gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= diff --git a/pkg/analyzer/content_test.go b/pkg/analyzer/content_test.go index 9289d95..0aa7ff9 100644 --- a/pkg/analyzer/content_test.go +++ b/pkg/analyzer/content_test.go @@ -76,17 +76,17 @@ func TestExtractTextFromHTML(t *testing.T) { { name: "Multiple elements", html: "

Title

Paragraph

", - expectedText: "Title Paragraph", + expectedText: "TitleParagraph", }, { name: "With script tag", html: "

Text

More

", - expectedText: "Text More", + expectedText: "TextMore", }, { name: "With style tag", html: "

Text

More

", - expectedText: "Text More", + expectedText: "TextMore", }, { name: "Empty HTML", diff --git a/pkg/analyzer/dns.go b/pkg/analyzer/dns.go index cb1fa68..57226c6 100644 --- a/pkg/analyzer/dns.go +++ b/pkg/analyzer/dns.go @@ -22,6 +22,7 @@ package analyzer import ( + "net" "time" "git.happydns.org/happyDeliver/internal/api" @@ -30,26 +31,19 @@ import ( // DNSAnalyzer analyzes DNS records for email domains type DNSAnalyzer struct { Timeout time.Duration - resolver DNSResolver + resolver *net.Resolver } // NewDNSAnalyzer creates a new DNS analyzer with configurable timeout func NewDNSAnalyzer(timeout time.Duration) *DNSAnalyzer { - return NewDNSAnalyzerWithResolver(timeout, NewStandardDNSResolver()) -} - -// NewDNSAnalyzerWithResolver creates a new DNS analyzer with a custom resolver. -// If resolver is nil, a StandardDNSResolver will be used. -func NewDNSAnalyzerWithResolver(timeout time.Duration, resolver DNSResolver) *DNSAnalyzer { if timeout == 0 { timeout = 10 * time.Second // Default timeout } - if resolver == nil { - resolver = NewStandardDNSResolver() - } return &DNSAnalyzer{ - Timeout: timeout, - resolver: resolver, + Timeout: timeout, + resolver: &net.Resolver{ + PreferGo: true, + }, } } @@ -127,12 +121,6 @@ func (d *DNSAnalyzer) AnalyzeDNS(email *EmailMessage, authResults *api.Authentic // Check BIMI record (for From domain - branding is based on visible sender) results.BimiRecord = d.checkBIMIRecord(fromDomain, "default") - // Check DNSSEC status (for From domain) - dnssecEnabled, err := d.resolver.IsDNSSECEnabled(nil, fromDomain) - if err == nil { - results.DnssecEnabled = &dnssecEnabled - } - return results } @@ -155,12 +143,6 @@ func (d *DNSAnalyzer) AnalyzeDomainOnly(domain string) *api.DNSResults { // Check BIMI record with default selector results.BimiRecord = d.checkBIMIRecord(domain, "default") - // Check DNSSEC status - dnssecEnabled, err := d.resolver.IsDNSSECEnabled(nil, domain) - if err == nil { - results.DnssecEnabled = &dnssecEnabled - } - return results } @@ -216,16 +198,11 @@ func (d *DNSAnalyzer) CalculateDNSScore(results *api.DNSResults, senderIP string score := 0 - // DNSSEC: 10 points - if results.DnssecEnabled != nil && *results.DnssecEnabled { - score += 10 - } - // PTR and Forward DNS: 20 points score += 20 * d.calculatePTRScore(results, senderIP) / 100 - // MX Records: 10 points (5 for From domain, 5 for Return-Path domain) - score += 10 * d.calculateMXScore(results) / 100 + // MX Records: 20 points (10 for From domain, 10 for Return-Path domain) + score += 20 * d.calculateMXScore(results) / 100 // SPF Records: 20 points score += 20 * d.calculateSPFScore(results) / 100 diff --git a/pkg/analyzer/dns_resolver.go b/pkg/analyzer/dns_resolver.go deleted file mode 100644 index dcbca59..0000000 --- a/pkg/analyzer/dns_resolver.go +++ /dev/null @@ -1,237 +0,0 @@ -// This file is part of the happyDeliver (R) project. -// Copyright (c) 2025 happyDomain -// Authors: Pierre-Olivier Mercier, et al. -// -// This program is offered under a commercial and under the AGPL license. -// For commercial licensing, contact us at . -// -// For AGPL licensing: -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package analyzer - -import ( - "context" - "fmt" - "net" - "strings" - - "github.com/miekg/dns" - "github.com/peterzen/goresolver" -) - -// DNSResolver defines the interface for DNS resolution operations. -// This interface abstracts DNS lookups to allow for custom implementations, -// such as mock resolvers for testing or caching resolvers for performance. -type DNSResolver interface { - // LookupMX returns the DNS MX records for the given domain. - LookupMX(ctx context.Context, name string) ([]*net.MX, error) - - // LookupTXT returns the DNS TXT records for the given domain. - LookupTXT(ctx context.Context, name string) ([]string, error) - - // LookupAddr performs a reverse lookup for the given IP address, - // returning a list of hostnames mapping to that address. - LookupAddr(ctx context.Context, addr string) ([]string, error) - - // LookupHost looks up the given hostname using the local resolver. - // It returns a slice of that host's addresses (IPv4 and IPv6). - LookupHost(ctx context.Context, host string) ([]string, error) - - // IsDNSSECEnabled checks if the given domain has DNSSEC enabled by querying for DNSKEY records. - // Returns true if the domain has DNSSEC configured and the chain of trust is valid. - IsDNSSECEnabled(ctx context.Context, domain string) (bool, error) -} - -// StandardDNSResolver is the default DNS resolver implementation that uses goresolver with DNSSEC validation. -type StandardDNSResolver struct { - resolver *goresolver.Resolver -} - -// NewStandardDNSResolver creates a new StandardDNSResolver with DNSSEC validation support. -func NewStandardDNSResolver() DNSResolver { - // Pass /etc/resolv.conf to load default DNS configuration - resolver, err := goresolver.NewResolver("/etc/resolv.conf") - if err != nil { - panic(fmt.Sprintf("failed to initialize goresolver: %v", err)) - } - - return &StandardDNSResolver{ - resolver: resolver, - } -} - -// LookupMX implements DNSResolver.LookupMX using goresolver with DNSSEC validation. -func (r *StandardDNSResolver) LookupMX(ctx context.Context, name string) ([]*net.MX, error) { - // Ensure the name ends with a dot for DNS queries - queryName := name - if !strings.HasSuffix(queryName, ".") { - queryName = queryName + "." - } - - rrs, err := r.resolver.StrictNSQuery(queryName, dns.TypeMX) - if err != nil { - return nil, err - } - - mxRecords := make([]*net.MX, 0, len(rrs)) - for _, rr := range rrs { - if mx, ok := rr.(*dns.MX); ok { - mxRecords = append(mxRecords, &net.MX{ - Host: strings.TrimSuffix(mx.Mx, "."), - Pref: mx.Preference, - }) - } - } - - if len(mxRecords) == 0 { - return nil, fmt.Errorf("no MX records found for %s", name) - } - - return mxRecords, nil -} - -// LookupTXT implements DNSResolver.LookupTXT using goresolver with DNSSEC validation. -func (r *StandardDNSResolver) LookupTXT(ctx context.Context, name string) ([]string, error) { - // Ensure the name ends with a dot for DNS queries - queryName := name - if !strings.HasSuffix(queryName, ".") { - queryName = queryName + "." - } - - rrs, err := r.resolver.StrictNSQuery(queryName, dns.TypeTXT) - if err != nil { - return nil, err - } - - txtRecords := make([]string, 0, len(rrs)) - for _, rr := range rrs { - if txt, ok := rr.(*dns.TXT); ok { - // Join all TXT strings (a single TXT record can have multiple strings) - txtRecords = append(txtRecords, strings.Join(txt.Txt, "")) - } - } - - if len(txtRecords) == 0 { - return nil, fmt.Errorf("no TXT records found for %s", name) - } - - return txtRecords, nil -} - -// LookupAddr implements DNSResolver.LookupAddr using goresolver with DNSSEC validation. -func (r *StandardDNSResolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { - // Convert IP address to reverse DNS name (e.g., 1.0.0.127.in-addr.arpa.) - arpa, err := dns.ReverseAddr(addr) - if err != nil { - return nil, fmt.Errorf("invalid IP address: %w", err) - } - - rrs, err := r.resolver.StrictNSQuery(arpa, dns.TypePTR) - if err != nil { - return nil, err - } - - ptrRecords := make([]string, 0, len(rrs)) - for _, rr := range rrs { - if ptr, ok := rr.(*dns.PTR); ok { - ptrRecords = append(ptrRecords, strings.TrimSuffix(ptr.Ptr, ".")) - } - } - - if len(ptrRecords) == 0 { - return nil, fmt.Errorf("no PTR records found for %s", addr) - } - - return ptrRecords, nil -} - -// LookupHost implements DNSResolver.LookupHost using goresolver with DNSSEC validation. -func (r *StandardDNSResolver) LookupHost(ctx context.Context, host string) ([]string, error) { - // Ensure the host ends with a dot for DNS queries - queryName := host - if !strings.HasSuffix(queryName, ".") { - queryName = queryName + "." - } - - var allAddrs []string - - // Query A records (IPv4) - rrsA, errA := r.resolver.StrictNSQuery(queryName, dns.TypeA) - if errA == nil { - for _, rr := range rrsA { - if a, ok := rr.(*dns.A); ok { - allAddrs = append(allAddrs, a.A.String()) - } - } - } - - // Query AAAA records (IPv6) - rrsAAAA, errAAAA := r.resolver.StrictNSQuery(queryName, dns.TypeAAAA) - if errAAAA == nil { - for _, rr := range rrsAAAA { - if aaaa, ok := rr.(*dns.AAAA); ok { - allAddrs = append(allAddrs, aaaa.AAAA.String()) - } - } - } - - // Return error only if both queries failed - if errA != nil && errAAAA != nil { - return nil, fmt.Errorf("failed to resolve host: IPv4 error: %v, IPv6 error: %v", errA, errAAAA) - } - - if len(allAddrs) == 0 { - return nil, fmt.Errorf("no A or AAAA records found for %s", host) - } - - return allAddrs, nil -} - -// IsDNSSECEnabled checks if the given domain has DNSSEC enabled by querying for DNSKEY records. -// It uses DNSSEC validation to ensure the chain of trust is valid. -// Returns true if DNSSEC is properly configured and validated, false otherwise. -func (r *StandardDNSResolver) IsDNSSECEnabled(ctx context.Context, domain string) (bool, error) { - // Ensure the domain ends with a dot for DNS queries - queryName := domain - if !strings.HasSuffix(queryName, ".") { - queryName = queryName + "." - } - - // Query for DNSKEY records with DNSSEC validation - // If this succeeds, it means: - // 1. The domain has DNSKEY records (DNSSEC is configured) - // 2. The DNSSEC chain of trust is valid (validated by StrictNSQuery) - rrs, err := r.resolver.StrictNSQuery(queryName, dns.TypeDNSKEY) - if err != nil { - // DNSSEC is not enabled or validation failed - return false, nil - } - - // Check if we got any DNSKEY records - if len(rrs) == 0 { - return false, nil - } - - // Verify we actually have DNSKEY records (not just any RR type) - hasDNSKEY := false - for _, rr := range rrs { - if _, ok := rr.(*dns.DNSKEY); ok { - hasDNSKEY = true - break - } - } - - return hasDNSKEY, nil -} diff --git a/pkg/analyzer/dns_resolver_test.go b/pkg/analyzer/dns_resolver_test.go deleted file mode 100644 index 7c9091b..0000000 --- a/pkg/analyzer/dns_resolver_test.go +++ /dev/null @@ -1,111 +0,0 @@ -// This file is part of the happyDeliver (R) project. -// Copyright (c) 2025 happyDomain -// Authors: Pierre-Olivier Mercier, et al. -// -// This program is offered under a commercial and under the AGPL license. -// For commercial licensing, contact us at . -// -// For AGPL licensing: -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package analyzer - -import ( - "context" - "testing" -) - -func TestIsDNSSECEnabled(t *testing.T) { - resolver := NewStandardDNSResolver() - ctx := context.Background() - - tests := []struct { - name string - domain string - expectDNSSEC bool - }{ - { - name: "ietf.org has DNSSEC", - domain: "ietf.org", - expectDNSSEC: true, - }, - { - name: "google.com doesn't have DNSSEC", - domain: "google.com", - expectDNSSEC: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - enabled, err := resolver.IsDNSSECEnabled(ctx, tt.domain) - if err != nil { - t.Errorf("IsDNSSECEnabled() error = %v", err) - return - } - - if enabled != tt.expectDNSSEC { - t.Errorf("IsDNSSECEnabled() for %s = %v, want %v", tt.domain, enabled, tt.expectDNSSEC) - } else { - // Log the result even if we're not validating - if enabled { - t.Logf("%s: DNSSEC is enabled ✅", tt.domain) - } else { - t.Logf("%s: DNSSEC is NOT enabled ⚠️", tt.domain) - } - } - }) - } -} - -func TestIsDNSSECEnabled_NonExistentDomain(t *testing.T) { - resolver := NewStandardDNSResolver() - ctx := context.Background() - - // Test with a domain that doesn't exist - enabled, err := resolver.IsDNSSECEnabled(ctx, "this-domain-definitely-does-not-exist-12345.com") - if err != nil { - // Error is acceptable for non-existent domains - t.Logf("Non-existent domain returned error (expected): %v", err) - return - } - - // If no error, DNSSEC should be disabled - if enabled { - t.Error("IsDNSSECEnabled() for non-existent domain should return false") - } -} - -func TestIsDNSSECEnabled_WithTrailingDot(t *testing.T) { - resolver := NewStandardDNSResolver() - ctx := context.Background() - - // Test that both formats work - domain1 := "cloudflare.com" - domain2 := "cloudflare.com." - - enabled1, err1 := resolver.IsDNSSECEnabled(ctx, domain1) - if err1 != nil { - t.Errorf("IsDNSSECEnabled() without trailing dot error = %v", err1) - } - - enabled2, err2 := resolver.IsDNSSECEnabled(ctx, domain2) - if err2 != nil { - t.Errorf("IsDNSSECEnabled() with trailing dot error = %v", err2) - } - - if enabled1 != enabled2 { - t.Errorf("IsDNSSECEnabled() results differ: without dot = %v, with dot = %v", enabled1, enabled2) - } -} diff --git a/pkg/analyzer/headers_test.go b/pkg/analyzer/headers_test.go index 2513e6f..6a35d18 100644 --- a/pkg/analyzer/headers_test.go +++ b/pkg/analyzer/headers_test.go @@ -83,8 +83,8 @@ func TestCalculateHeaderScore(t *testing.T) { Date: "Mon, 01 Jan 2024 12:00:00 +0000", Parts: []MessagePart{{ContentType: "text/plain", Content: "test"}}, }, - minScore: 80, - maxScore: 90, + minScore: 40, + maxScore: 80, }, { name: "Invalid Message-ID format", diff --git a/pkg/analyzer/parser_test.go b/pkg/analyzer/parser_test.go index eb1fc6a..571f542 100644 --- a/pkg/analyzer/parser_test.go +++ b/pkg/analyzer/parser_test.go @@ -106,9 +106,6 @@ Content-Type: text/html; charset=utf-8 } func TestGetAuthenticationResults(t *testing.T) { - // Force hostname - hostname = "example.com" - rawEmail := `From: sender@example.com To: recipient@example.com Subject: Test Email diff --git a/web/src/lib/components/DnsRecordsCard.svelte b/web/src/lib/components/DnsRecordsCard.svelte index 1bf02f7..337f7c1 100644 --- a/web/src/lib/components/DnsRecordsCard.svelte +++ b/web/src/lib/components/DnsRecordsCard.svelte @@ -10,7 +10,6 @@ import BimiRecordDisplay from "./BimiRecordDisplay.svelte"; import PtrRecordsDisplay from "./PtrRecordsDisplay.svelte"; import PtrForwardRecordsDisplay from "./PtrForwardRecordsDisplay.svelte"; - import DnssecDisplay from "./DnssecDisplay.svelte"; interface Props { domainAlignment?: DomainAlignment; @@ -151,9 +150,6 @@ - - - {/if} diff --git a/web/src/lib/components/DnssecDisplay.svelte b/web/src/lib/components/DnssecDisplay.svelte deleted file mode 100644 index a795ebd..0000000 --- a/web/src/lib/components/DnssecDisplay.svelte +++ /dev/null @@ -1,56 +0,0 @@ - - -{#if dnssecEnabled !== undefined} -
-
-
- - DNSSEC -
- Security -
-
-

- DNSSEC (DNS Security Extensions) adds cryptographic signatures to DNS records to verify - their authenticity and integrity. It protects against DNS spoofing and cache poisoning - attacks, ensuring that DNS responses haven't been tampered with. -

- {#if domain} -
- Domain: {domain} -
- {/if} - {#if dnssecIsValid} -
- - Enabled: DNSSEC is properly configured with a valid chain of trust. - This provides additional security and authenticity for your domain's DNS records. -
- {:else} -
- - Not Enabled: DNSSEC is not configured for this domain. While not - required for email delivery, enabling DNSSEC provides additional security by protecting - against DNS-based attacks. Consider enabling DNSSEC through your domain registrar or - DNS provider. -
- {/if} -
-
-{/if}