diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..fe7c01a --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +dotenv diff --git a/.gitignore b/.gitignore index a0b4c21..a5e2ec2 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ # Build artifacts dist/ + +# Local environment variables +.env diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..4933a41 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +golang 1.18 diff --git a/VERSION b/VERSION index d15723f..2b7c5ae 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.2 +0.4.2 diff --git a/cmd/emojictl/main.go b/cmd/emojictl/main.go index 20f34a8..91e8439 100644 --- a/cmd/emojictl/main.go +++ b/cmd/emojictl/main.go @@ -13,7 +13,11 @@ import ( ) func main() { - sec, err := emojictl.NewSlackEmojictl(os.Getenv("SLACK_TOKEN")) + sec, err := emojictl.NewSlackEmojictl( + os.Getenv("SLACK_WORKSPACE"), + os.Getenv("SLACK_HEADER_TOKEN"), + os.Getenv("SLACK_BODY_TOKEN"), + ) if err != nil { panic(err) } diff --git a/go.mod b/go.mod index 3769df3..b3796c8 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/gabriel-vasile/mimetype v1.4.0 + github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/jonboulle/clockwork v0.1.0 // indirect @@ -16,12 +17,14 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v0.9.3 // indirect - github.com/slack-go/slack v0.10.0 + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/slack-go/slack v0.10.2 github.com/soheilhy/cmux v0.1.4 // indirect - github.com/spf13/cobra v1.2.1 + github.com/spf13/cobra v1.4.0 + github.com/spf13/viper v1.8.1 // indirect github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect go.etcd.io/bbolt v1.3.2 // indirect - golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 // indirect + golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 // indirect gopkg.in/resty.v1 v1.12.0 // indirect ) diff --git a/go.sum b/go.sum index d3b33d3..f1c6f99 100644 --- a/go.sum +++ b/go.sum @@ -67,6 +67,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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= @@ -165,6 +166,8 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= @@ -255,6 +258,7 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -265,6 +269,8 @@ github.com/slack-go/slack v0.9.5 h1:j7uOUDowybWf9eSgZg/AbGx6J1OPJB6SE8Z5dNl6Mtw= github.com/slack-go/slack v0.9.5/go.mod h1:wWL//kk0ho+FcQXcBTmEafUI5dz4qz5f4mMk8oIkioQ= github.com/slack-go/slack v0.10.0 h1:L16Eqg3QZzRKGXIVsFSZdJdygjOphb2FjRUwH6VrFu8= github.com/slack-go/slack v0.10.0/go.mod h1:wWL//kk0ho+FcQXcBTmEafUI5dz4qz5f4mMk8oIkioQ= +github.com/slack-go/slack v0.10.2 h1:KMN/h2sgUninHXvQI8PrR/PHBUuWp2NPvz2Kr66tki4= +github.com/slack-go/slack v0.10.2/go.mod h1:5FLdBRv7VW/d9EBxx/eEktOptWygbA9K2QK/KW7ds1s= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -277,6 +283,8 @@ github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -406,6 +414,8 @@ golang.org/x/net v0.0.0-20211020060615-d418f374d309 h1:A0lJIi+hcTR6aajJH4YqKWwoh golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 h1:0qxwC5n+ttVOINCBeRHO0nq9X7uy8SDsPoi5OaCdIEI= golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c= +golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -474,7 +484,10 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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/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/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -483,6 +496,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/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/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/pkg/emojictl/emojictl.go b/pkg/emojictl/emojictl.go index f675c33..ebb3caf 100644 --- a/pkg/emojictl/emojictl.go +++ b/pkg/emojictl/emojictl.go @@ -47,8 +47,9 @@ const ( // All supported HTTP headers in this project type HTTPHeaders struct { - ContentType string `header:"Content-Type"` ContentDisposition string `header:"Content-Disposition"` + ContentType string `header:"Content-Type"` + Cookie string `header:"Cookie"` } // ToMapStringSliceString is a helper to make HTTPHeaders compatible with diff --git a/pkg/emojictl/emojictl_slack.go b/pkg/emojictl/emojictl_slack.go index 5c79a1b..c428d99 100644 --- a/pkg/emojictl/emojictl_slack.go +++ b/pkg/emojictl/emojictl_slack.go @@ -50,12 +50,12 @@ func (s *slackHTTPResponse) JSON() (map[string]interface{}, error) { } type slackHTTPClient struct { - httpClient http.Client - token string + httpClient http.Client + headerToken, bodyToken, workspace string } func (s *slackHTTPClient) defaultMultipartBody() MultipartBody { - return MultipartBody(map[string]string{"token": s.token}) + return MultipartBody(map[string]string{"token": s.bodyToken}) } func (s *slackHTTPClient) Do(req *slackHTTPRequest) (*slackHTTPResponse, error) { @@ -67,18 +67,29 @@ func (s *slackHTTPClient) Do(req *slackHTTPRequest) (*slackHTTPResponse, error) res, err := s.httpClient.Do(func() *http.Request { return &http.Request{ Method: string(req.Method), - URL: &url.URL{Scheme: "https", Host: slackHost, Path: req.Path}, + URL: &url.URL{ + Scheme: "https", + Host: fmt.Sprintf("%s.%s", s.workspace, slackHost), + Path: req.Path, + }, Header: func() http.Header { - multipartContentTypeHeader := MakeMultiPartContentTypeHeaderValue(boundary) + multipartContentTypeHeader := MakeMultiPartContentTypeHeaderValue( + boundary, + ) if req.Headers == nil { return HTTPHeaders{ ContentType: multipartContentTypeHeader, + Cookie: fmt.Sprintf( + "d=%s", url.QueryEscape(s.headerToken), + ), }.ToMapStringSliceString() } if _, ok := req.Headers[string(ContentType)]; !ok { - req.Headers.Set(string(ContentType), multipartContentTypeHeader) + req.Headers.Set( + string(ContentType), multipartContentTypeHeader, + ) } return req.Headers @@ -101,13 +112,16 @@ type SlackEmojictl struct { slackHTTPClient *slackHTTPClient } -func NewSlackEmojictl(token string) (*SlackEmojictl, error) { +func NewSlackEmojictl(workspace, headerToken, bodyToken string) (*SlackEmojictl, error) { return &SlackEmojictl{ - slack.New(token), &slackHTTPClient{*http.DefaultClient, token}, + slack.New(headerToken), + &slackHTTPClient{*http.DefaultClient, headerToken, bodyToken, workspace}, }, nil } -func (s *SlackEmojictl) makeEmojiMultipartBody(e *Emoji) (string, io.ReadCloser, error) { +func (s *SlackEmojictl) makeEmojiMultipartBody(e *Emoji) ( + string, io.ReadCloser, error, +) { eBytes, err := e.Get() if err != nil { return "", nil, err @@ -120,7 +134,7 @@ func (s *SlackEmojictl) makeEmojiMultipartBody(e *Emoji) (string, io.ReadCloser, for k, v := range map[string]string{ "mode": "data", "name": e.Name, - "token": s.slackHTTPClient.token, + "token": s.slackHTTPClient.bodyToken, } { if err := mpWriter.WriteField(k, v); err != nil { return "", nil, err @@ -128,8 +142,10 @@ func (s *SlackEmojictl) makeEmojiMultipartBody(e *Emoji) (string, io.ReadCloser, } imageBody, err := mpWriter.CreatePart(textproto.MIMEHeader(HTTPHeaders{ - ContentDisposition: fmt.Sprintf("form-data; name=image; filename=\"%s\"", fName), - ContentType: mimetype.Detect(eBytes).String(), + ContentDisposition: fmt.Sprintf( + "form-data; name=image; filename=\"%s\"", fName, + ), + ContentType: mimetype.Detect(eBytes).String(), }.ToMapStringSliceString())) if err != nil { return "", nil, err @@ -159,6 +175,10 @@ func (s *SlackEmojictl) ListEmojis(ctx context.Context) ([]*Emoji, error) { return nil, err } + if resJSON["ok"] == false { + return nil, fmt.Errorf("encountered Slack API error: %+v", resJSON["error"]) + } + emojis := []*Emoji{} for name, image := range resJSON["emoji"].(map[string]interface{}) { u, err := url.Parse(image.(string)) @@ -214,7 +234,7 @@ func (s *SlackEmojictl) AddEmoji(ctx context.Context, e *Emoji) error { func (s *SlackEmojictl) RemoveEmoji(ctx context.Context, e *Emoji) error { bound, body, err := MultipartBody(map[string]string{ "name": e.Name, - "token": s.slackHTTPClient.token, + "token": s.slackHTTPClient.bodyToken, }).Render() if err != nil { return err @@ -245,7 +265,7 @@ func (s *SlackEmojictl) AliasEmoji(ctx context.Context, src, dest string) error "mode": "alias", "name": src, "alias_for": fmt.Sprintf(":%s:", dest), - "token": s.slackHTTPClient.token, + "token": s.slackHTTPClient.bodyToken, }).Render() if err != nil { return err