Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Lavender and Tulip #3

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Start merging lavender and tulip
mrmelon54 committed Aug 19, 2024
commit a81aa0458a40e7b1c0e4615bbc847cefd738d3c8
3 changes: 3 additions & 0 deletions conf/conf.go
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ package conf

import (
"github.com/1f349/lavender/issuer"
"github.com/1f349/lavender/mail"
)

type Conf struct {
@@ -10,5 +11,7 @@ type Conf struct {
ServiceName string `yaml:"serviceName"`
Issuer string `yaml:"issuer"`
Kid string `yaml:"kid"`
Namespace string `yaml:"namespace"`
Mail mail.Mail `yaml:"mail"`
SsoServices []issuer.SsoConfig `yaml:"ssoServices"`
}
12 changes: 8 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -6,8 +6,12 @@ require (
github.com/1f349/cache v0.0.3
github.com/1f349/mjwt v0.4.1
github.com/1f349/overlapfs v0.0.1
github.com/1f349/tulip v0.0.0-20240725211619-6b19e2d4ca63
github.com/charmbracelet/log v0.4.0
github.com/cloudflare/tableflip v1.2.3
github.com/emersion/go-message v0.18.1
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43
github.com/emersion/go-smtp v0.21.3
github.com/go-oauth2/oauth2/v4 v4.5.2
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang-migrate/migrate/v4 v4.17.1
@@ -17,7 +21,9 @@ require (
github.com/mattn/go-sqlite3 v1.14.22
github.com/spf13/afero v1.11.0
github.com/stretchr/testify v1.9.0
golang.org/x/crypto v0.26.0
golang.org/x/oauth2 v0.22.0
golang.org/x/text v0.17.0
gopkg.in/yaml.v3 v3.0.1
)

@@ -31,7 +37,7 @@ require (
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/klauspost/compress v1.17.9 // indirect
@@ -53,10 +59,8 @@ require (
github.com/tidwall/rtred v0.1.2 // indirect
github.com/tidwall/tinyqueue v0.1.1 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
)
39 changes: 35 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -7,6 +7,8 @@ github.com/1f349/overlapfs v0.0.1 h1:LAxBolrXFAgU0yqZtXg/C/aaPq3eoQSPpBc49BHuTp0
github.com/1f349/overlapfs v0.0.1/go.mod h1:I6aItQycr7nrzplmfNXp/QF9tTmKRSgY3fXmu/7Ky2o=
github.com/1f349/rsa-helper v0.0.2 h1:N/fLQqg5wrjIzG6G4zdwa5Xcv9/jIPutCls9YekZr9U=
github.com/1f349/rsa-helper v0.0.2/go.mod h1:VUQ++1tYYhYrXeOmVFkQ82BegR24HQEJHl5lHbjg7yg=
github.com/1f349/tulip v0.0.0-20240725211619-6b19e2d4ca63 h1:jPg+0bgKD5kY7yQtRZqeba+BGKFE51evGvwewZwa7Xc=
github.com/1f349/tulip v0.0.0-20240725211619-6b19e2d4ca63/go.mod h1:1zFQhcbgiyPSWHVMp0cXJjmd6FhasP5bf5tWS4ZK61A=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
@@ -27,6 +29,13 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
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-message v0.18.1 h1:tfTxIoXFSFRwWaZsgnqS1DSZuGpYGzSmCZD8SK3QA2E=
github.com/emersion/go-message v0.18.1/go.mod h1:XpJyL70LwRvq2a8rVbHXikPgKj8+aI0kGdHlg16ibYA=
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 h1:hH4PQfOndHDlpzYfLAAfl63E8Le6F2+EL/cdhlkyRJY=
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-smtp v0.21.3 h1:7uVwagE8iPYE48WhNsng3RRpCUpFvNl39JGNSIyGVMY=
github.com/emersion/go-smtp v0.21.3/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
@@ -72,8 +81,8 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
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/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -193,29 +202,40 @@ github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FB
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
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=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -233,19 +253,30 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
104 changes: 104 additions & 0 deletions lists/locales.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package lists

import (
"golang.org/x/text/language"
"golang.org/x/text/language/display"
"sync"
)

var (
localeOnce sync.Once
localeNames []struct{ Value, Label string }
)

func ListLocale() []struct{ Value, Label string } {
localeOnce.Do(func() {
localeNames = make([]struct{ Value, Label string }, len(localeList))
for i := range localeList {
localeNames[i] = struct{ Value, Label string }{Value: localeList[i].String(), Label: display.Self.Name(localeList[i])}
}
})
return localeNames
}

var localeList = []language.Tag{
language.Afrikaans,
language.Amharic,
language.Arabic,
language.ModernStandardArabic,
language.Azerbaijani,
language.Bulgarian,
language.Bengali,
language.Catalan,
language.Czech,
language.Danish,
language.German,
language.Greek,
language.English,
language.AmericanEnglish,
language.BritishEnglish,
language.Spanish,
language.EuropeanSpanish,
language.LatinAmericanSpanish,
language.Estonian,
language.Persian,
language.Finnish,
language.Filipino,
language.French,
language.CanadianFrench,
language.Gujarati,
language.Hebrew,
language.Hindi,
language.Croatian,
language.Hungarian,
language.Armenian,
language.Indonesian,
language.Icelandic,
language.Italian,
language.Japanese,
language.Georgian,
language.Kazakh,
language.Khmer,
language.Kannada,
language.Korean,
language.Kirghiz,
language.Lao,
language.Lithuanian,
language.Latvian,
language.Macedonian,
language.Malayalam,
language.Mongolian,
language.Marathi,
language.Malay,
language.Burmese,
language.Nepali,
language.Dutch,
language.Norwegian,
language.Punjabi,
language.Polish,
language.Portuguese,
language.BrazilianPortuguese,
language.EuropeanPortuguese,
language.Romanian,
language.Russian,
language.Sinhala,
language.Slovak,
language.Slovenian,
language.Albanian,
language.Serbian,
language.SerbianLatin,
language.Swedish,
language.Swahili,
language.Tamil,
language.Telugu,
language.Thai,
language.Turkish,
language.Ukrainian,
language.Urdu,
language.Uzbek,
language.Vietnamese,
language.Chinese,
language.SimplifiedChinese,
language.TraditionalChinese,
language.Zulu,
}
15 changes: 15 additions & 0 deletions lists/locales_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package lists

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestListLocale(t *testing.T) {
locales := ListLocale()
assert.True(t, len(locales) > 4)
assert.Equal(t, struct{ Value, Label string }{Value: "af", Label: "Afrikaans"}, locales[0])
assert.Equal(t, struct{ Value, Label string }{Value: "am", Label: "አማርኛ"}, locales[1])
assert.Equal(t, struct{ Value, Label string }{Value: "zh-Hant", Label: "繁體中文"}, locales[len(locales)-2])
assert.Equal(t, struct{ Value, Label string }{Value: "zu", Label: "isiZulu"}, locales[len(locales)-1])
}
53 changes: 53 additions & 0 deletions lists/zoneinfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package lists

import (
"os"
"path/filepath"
"sort"
"strings"
"sync"
)

var (
zoneDirs = []string{
// Update path according to your OS
"/usr/share/zoneinfo/",
"/usr/share/lib/zoneinfo/",
"/usr/lib/locale/TZ/",
}
zoneInfoOnce sync.Once
zoneNames []string
)

func ListZoneInfo() []string {
zoneInfoOnce.Do(func() {
zoneNames = make([]string, 0)
for _, zoneDir := range zoneDirs {
zoneNames = append(zoneNames, FindTimeZoneFiles(zoneDir)...)
}
sort.Strings(zoneNames)
})
return zoneNames
}

func FindTimeZoneFiles(zoneDir string) []string {
dArr := make([]string, 0)
dArr = append(dArr, "")
arr := make([]string, 0)

for i := 0; i < len(dArr); i++ {
dir := dArr[i]
files, _ := os.ReadDir(filepath.Join(zoneDir, dir))
for _, f := range files {
if f.Name() != strings.ToUpper(f.Name()[:1])+f.Name()[1:] {
continue
}
if f.IsDir() {
dArr = append(dArr, filepath.Join(dir, f.Name()))
} else {
arr = append(arr, filepath.Join(dir, f.Name()))
}
}
}
return arr
}
15 changes: 15 additions & 0 deletions lists/zoneinfo_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package lists

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestListZoneInfo(t *testing.T) {
zoneinfos := ListZoneInfo()
assert.True(t, len(zoneinfos) > 4)
assert.Equal(t, "Africa/Abidjan", zoneinfos[0])
assert.Equal(t, "Africa/Accra", zoneinfos[1])
assert.Equal(t, "WET", zoneinfos[len(zoneinfos)-2])
assert.Equal(t, "Zulu", zoneinfos[len(zoneinfos)-1])
}
26 changes: 26 additions & 0 deletions mail/from-address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package mail

import (
"encoding/json"
"github.com/emersion/go-message/mail"
)

type FromAddress struct {
*mail.Address
}

var _ json.Unmarshaler = &FromAddress{}

func (f *FromAddress) UnmarshalJSON(b []byte) error {
var a string
err := json.Unmarshal(b, &a)
if err != nil {
return err
}
address, err := mail.ParseAddress(a)
if err != nil {
return err
}
f.Address = address
return nil
}
96 changes: 96 additions & 0 deletions mail/mail.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package mail

import (
"bytes"
"github.com/emersion/go-message/mail"
"github.com/emersion/go-sasl"
"github.com/emersion/go-smtp"
"io"
"net"
"time"
)

type Mail struct {
Name string `json:"name"`
Tls bool `json:"tls"`
Server string `json:"server"`
From FromAddress `json:"from"`
Username string `json:"username"`
Password string `json:"password"`
}

func (m *Mail) loginInfo() sasl.Client {
return sasl.NewPlainClient("", m.Username, m.Password)
}

func (m *Mail) mailCall(to []string, r io.Reader) error {
host, _, err := net.SplitHostPort(m.Server)
if err != nil {
return err
}
if m.Tls {
return smtp.SendMailTLS(m.Server, m.loginInfo(), m.From.String(), to, r)
}
if host == "localhost" || host == "127.0.0.1" {
// internals of smtp.SendMail without STARTTLS for localhost testing
dial, err := smtp.Dial(m.Server)
if err != nil {
return err
}
err = dial.Auth(m.loginInfo())
if err != nil {
return err
}
return dial.SendMail(m.From.String(), to, r)
}
return smtp.SendMail(m.Server, m.loginInfo(), m.From.String(), to, r)
}

func (m *Mail) SendMail(subject string, to []*mail.Address, htmlBody, textBody io.Reader) error {
// generate the email in this template
buf := new(bytes.Buffer)

// setup mail headers
var h mail.Header
h.SetDate(time.Now())
h.SetSubject(subject)
h.SetAddressList("From", []*mail.Address{m.From.Address})
h.SetAddressList("To", to)
h.Set("Content-Type", "multipart/alternative")

// setup html and text alternative headers
var hHtml, hTxt mail.InlineHeader
hHtml.Set("Content-Type", "text/html; charset=utf-8")
hTxt.Set("Content-Type", "text/plain; charset=utf-8")

createWriter, err := mail.CreateWriter(buf, h)
if err != nil {
return err
}
inline, err := createWriter.CreateInline()
if err != nil {
return err
}
partHtml, err := inline.CreatePart(hHtml)
if err != nil {
return err
}
if _, err := io.Copy(partHtml, htmlBody); err != nil {
return err
}
partTxt, err := inline.CreatePart(hTxt)
if err != nil {
return err
}
if _, err := io.Copy(partTxt, textBody); err != nil {
return err
}

// convert all to addresses to strings
toStr := make([]string, len(to))
for i := range toStr {
toStr[i] = to[i].String()
}

return m.mailCall(toStr, buf)
}
18 changes: 18 additions & 0 deletions mail/send-template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package mail

import (
"bytes"
"fmt"
"github.com/1f349/lavender/mail/templates"
"github.com/emersion/go-message/mail"
)

func (m *Mail) SendEmailTemplate(templateName, subject, nameOfUser string, to *mail.Address, data map[string]any) error {
var bufHtml, bufTxt bytes.Buffer
templates.RenderMailTemplate(&bufHtml, &bufTxt, templateName, map[string]any{
"ServiceName": m.Name,
"Name": nameOfUser,
"Data": data,
})
return m.SendMail(fmt.Sprintf("%s - %s", subject, m.Name), []*mail.Address{to}, &bufHtml, &bufTxt)
}
10 changes: 10 additions & 0 deletions mail/templates/mail-account-delete.go.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<body>
<p>Hello, {{.Name}}</p>
<p>Your account with {{.ServiceName}} has been disabled and marked for deletion.</p>
<p>Your account will be fully deleted within 48-hours.</p>
<p>You will no longer receive emails from {{.ServiceName}}, unless your email address is used to set up an account.</p>
<p>Regards,<br/>{{.ServiceName}}</p>
</body>
</html>
10 changes: 10 additions & 0 deletions mail/templates/mail-account-delete.go.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Hello, {{.Name}}

Your account with {{.ServiceName}} has been disabled and marked for deletion.

Your account will be fully deleted within 48-hours.

You will no longer receive emails from {{.ServiceName}}, unless your email address is used to set up an account.

Regards,
{{.ServiceName}}
11 changes: 11 additions & 0 deletions mail/templates/mail-register-admin.go.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<body>
<p>Hello, {{.Name}}</p>
<p>Your email address has been registered with {{.ServiceName}} by an administrator.</p>
<p>Please open this link to verify your email address and <a href="{{.Data.RegisterUrl}}" target="_blank">register your account</a></p>
<p>If you did not wish to register for {{.ServiceName}}, then your email has probably been used by mistake.</p>
<p>If the link above is not used to register an account, then no further contact will be made from {{.ServiceName}} and your email address will be deleted from our systems within a 48-hour period.</p>
<p>Regards,<br/>{{.ServiceName}}</p>
</body>
</html>
12 changes: 12 additions & 0 deletions mail/templates/mail-register-admin.go.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Hello, {{.Name}}

Your email address has been registered with {{.ServiceName}} by an administrator.

Please open this link to verify your email address and register your account {{.Data.RegisterUrl}}

If you did not wish to register for {{.ServiceName}}, then your email has probably been used by mistake.

If the link above is not used to register an account, then no further contact will be made from {{.ServiceName}} and your email address will be deleted from our systems within a 48-hour period.

Regards,
{{.ServiceName}}
9 changes: 9 additions & 0 deletions mail/templates/mail-reset-password.go.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<body>
<p>Hello, {{.Name}}</p>
<p>Please open this link to <a href="{{.Data.ResetUrl}}" target="_blank">reset your password</a></p>
<p>This link is valid for 10 minutes.</p>
<p>Regards,<br/>{{.ServiceName}}</p>
</body>
</html>
8 changes: 8 additions & 0 deletions mail/templates/mail-reset-password.go.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Hello, {{.Name}}

Please open this link to reset your password: {{.Data.ResetUrl}}

This link is valid for 10 minutes.

Regards,
{{.ServiceName}}
10 changes: 10 additions & 0 deletions mail/templates/mail-verify.go.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<body>
<p>Hello, {{.Name}}</p>
<p>Please open this link to <a href="{{.Data.VerifyUrl}}" target="_blank">verify your email address</a></p>
<p>This link is valid for 10 minutes.</p>
<p>If you did not create an account with {{.ServiceName}} then please ignore this email and the account will be deleted within a 48-hour period.</p>
<p>Regards,<br/>{{.ServiceName}}</p>
</body>
</html>
10 changes: 10 additions & 0 deletions mail/templates/mail-verify.go.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Hello, {{.Name}}

Please open this link to verify your email address: {{.Data.VerifyUrl}}

This link is valid for 10 minutes.

If you did not create an account with {{.ServiceName}} then please ignore this email and the account will be deleted within a 48-hour period.

Regards,
{{.ServiceName}}
55 changes: 55 additions & 0 deletions mail/templates/templates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package templates

import (
"embed"
"errors"
"github.com/1f349/overlapfs"
"github.com/1f349/tulip/logger"
htmlTemplate "html/template"
"io"
"io/fs"
"os"
"path/filepath"
"sync"
textTemplate "text/template"
)

var (
//go:embed *.go.html *.go.txt
embeddedTemplates embed.FS
mailHtmlTemplates *htmlTemplate.Template
mailTextTemplates *textTemplate.Template
loadOnce sync.Once
)

func LoadMailTemplates(wd string) (err error) {
loadOnce.Do(func() {
var o fs.FS = embeddedTemplates
if wd != "" {
mailDir := filepath.Join(wd, "mail-templates")
err = os.Mkdir(mailDir, os.ModePerm)
if err != nil && !errors.Is(err, os.ErrExist) {
return
}
wdFs := os.DirFS(mailDir)
o = overlapfs.OverlapFS{A: embeddedTemplates, B: wdFs}
}
mailHtmlTemplates, err = htmlTemplate.New("mail").ParseFS(o, "*.go.html")
if err != nil {
return
}
mailTextTemplates, err = textTemplate.New("mail").ParseFS(o, "*.go.txt")
})
return
}

func RenderMailTemplate(wrHtml, wrTxt io.Writer, name string, data any) {
err := mailHtmlTemplates.ExecuteTemplate(wrHtml, name+".go.html", data)
if err != nil {
logger.Logger.Warn("Failed to render mail html", "name", name, "err", err)
}
err = mailTextTemplates.ExecuteTemplate(wrTxt, name+".go.txt", data)
if err != nil {
logger.Logger.Warn("Failed to render mail text", "name", name, "err", err)
}
}
17 changes: 17 additions & 0 deletions password/password.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package password

import (
"golang.org/x/crypto/bcrypt"
)

// HashString is used to represent a string containing a password hash
type HashString string

func HashPassword(password string) (HashString, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
return HashString(bytes), err
}

func CheckPasswordHash(hash HashString, password string) error {
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
}