From 853120f4ee50677618491315d547af3f39375bf2 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 22 Oct 2024 22:32:04 +0500 Subject: [PATCH] 0.0.2 --- internal/api/http/handlers/target/target.go | 14 ++- internal/api/http/handlers/widget/widget.go | 10 +- internal/model/api/auth.go | 10 ++ internal/model/interfaces.go | 6 + internal/model/types.go | 2 - pkg/api/auth/auth.go | 123 ++++++++++++++++++++ 6 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 internal/model/api/auth.go create mode 100644 pkg/api/auth/auth.go diff --git a/internal/api/http/handlers/target/target.go b/internal/api/http/handlers/target/target.go index 3d3b8bc..2287ac6 100644 --- a/internal/api/http/handlers/target/target.go +++ b/internal/api/http/handlers/target/target.go @@ -7,11 +7,10 @@ import ( "net/http" ) -func CreateTarget(targetService model.TargetService) echo.HandlerFunc { +func CreateTarget(targetService model.TargetService, authClient model.AuthClient) echo.HandlerFunc { type CreateTargetBody struct { - StreamerID model.StreamerID `json:"streamerID"` - Amount model.DonatAmount `json:"amount"` - Text string `json:"text"` + Amount model.DonatAmount `json:"amount"` + Text string `json:"text"` } return func(request echo.Context) error { ctx := context.Background() @@ -24,7 +23,12 @@ func CreateTarget(targetService model.TargetService) echo.HandlerFunc { return echo.NewHTTPError(400, err.Error()) } - err := targetService.CreateTarget(ctx, body.StreamerID, body.Amount, body.Text) + authData, err := authClient.CheckToken(request) + if err != nil { + return echo.NewHTTPError(400, err.Error()) + } + + err = targetService.CreateTarget(ctx, model.StreamerID(authData.StreamerID), body.Amount, body.Text) if err != nil { return request.JSON(http.StatusInternalServerError, err) } diff --git a/internal/api/http/handlers/widget/widget.go b/internal/api/http/handlers/widget/widget.go index a5255a4..3a5f51a 100644 --- a/internal/api/http/handlers/widget/widget.go +++ b/internal/api/http/handlers/widget/widget.go @@ -8,9 +8,8 @@ import ( "strconv" ) -func CreateWidget(widgetService model.WidgetService) echo.HandlerFunc { +func CreateWidget(widgetService model.WidgetService, authClient model.AuthClient) echo.HandlerFunc { type Body struct { - StreamerID model.StreamerID `json:"streamerID"` TemplateID model.TemplateID `json:"templateID"` MinAmount model.DonatAmount `json:"minAmount"` Duration model.Duration `json:"duration"` @@ -29,9 +28,14 @@ func CreateWidget(widgetService model.WidgetService) echo.HandlerFunc { return echo.NewHTTPError(400, err.Error()) } + authData, err := authClient.CheckToken(request) + if err != nil { + return echo.NewHTTPError(400, err.Error()) + } + widgetID, err := widgetService.CreateWidget( ctx, - body.StreamerID, + model.StreamerID(authData.StreamerID), body.TemplateID, body.Duration, body.MinAmount, diff --git a/internal/model/api/auth.go b/internal/model/api/auth.go new file mode 100644 index 0000000..1c17ad2 --- /dev/null +++ b/internal/model/api/auth.go @@ -0,0 +1,10 @@ +package api + +type CheckTokenResponse struct { + StreamerID int `json:"accountID"` + TwoFa bool `json:"twoFa"` +} + +type VerifyTokenResponse struct { + Verified bool `json:"verified"` +} diff --git a/internal/model/interfaces.go b/internal/model/interfaces.go index 69dc793..175afc5 100644 --- a/internal/model/interfaces.go +++ b/internal/model/interfaces.go @@ -4,6 +4,7 @@ import ( "context" "donat-widget/internal/model/api" "github.com/jackc/pgx/v5" + "github.com/labstack/echo/v4" "github.com/jackc/pgx/v5/pgconn" ) @@ -79,3 +80,8 @@ type Db interface { CreateTable(ctx context.Context, query string) error DropTable(ctx context.Context, query string) error } + +type AuthClient interface { + CheckToken(request echo.Context) (api.CheckTokenResponse, error) + VerifyTwoFa(twoFaCode string, streamerID StreamerID) (bool, error) +} diff --git a/internal/model/types.go b/internal/model/types.go index 68f2466..dbce64f 100644 --- a/internal/model/types.go +++ b/internal/model/types.go @@ -5,8 +5,6 @@ import ( "mime/multipart" ) -type QueryArgs map[string]any - type StreamerID int type WidgetID int type TemplateID int diff --git a/pkg/api/auth/auth.go b/pkg/api/auth/auth.go new file mode 100644 index 0000000..40757f4 --- /dev/null +++ b/pkg/api/auth/auth.go @@ -0,0 +1,123 @@ +package auth + +import ( + "bytes" + "donat-widget/internal/model" + "donat-widget/internal/model/api" + "encoding/json" + "errors" + "github.com/labstack/echo/v4" + "io" + "log/slog" + "net/http" + "strconv" +) + +func New(host, port string) *ClientAuth { + return &ClientAuth{ + client: &http.Client{}, + baseURL: "http://" + host + ":" + port + "/api/auth", + } +} + +type ClientAuth struct { + client *http.Client + baseURL string +} + +func (c *ClientAuth) CheckToken( + request echo.Context, +) (api.CheckTokenResponse, error) { + _accessToken, err := request.Cookie("Access-Token") + if err != nil { + slog.Error("request.Cookie: " + err.Error()) + return api.CheckTokenResponse{}, err + } + accessToken := _accessToken.Value + + req, err := http.NewRequest("GET", c.baseURL+"/token/check", nil) + if err != nil { + slog.Error("http.NewRequest: " + err.Error()) + return api.CheckTokenResponse{}, err + } + req.AddCookie(&http.Cookie{Name: "Access-Token", Value: accessToken}) + resp, err := c.client.Do(req) + if err != nil { + slog.Error("client.Do: " + err.Error()) + return api.CheckTokenResponse{}, err + } + if resp.StatusCode != http.StatusOK { + return api.CheckTokenResponse{}, errors.New("get failed: " + resp.Status) + } + + response, err := io.ReadAll(resp.Body) + if err != nil { + slog.Error("io.ReadAll: " + err.Error()) + return api.CheckTokenResponse{}, err + } + + var checkTokenResponse api.CheckTokenResponse + err = json.Unmarshal(response, &checkTokenResponse) + if err != nil { + slog.Error("json.Unmarshal: " + err.Error()) + return api.CheckTokenResponse{}, err + } + return checkTokenResponse, nil +} + +func (c *ClientAuth) VerifyTwoFa( + twoFaCode string, + streamerID model.StreamerID, +) (bool, error) { + _accountID := strconv.Itoa(int(streamerID)) + path := c.baseURL + "/twoFa/verify" + "/" + _accountID + "/" + string(twoFaCode) + req, err := http.NewRequest("GET", path, nil) + if err != nil { + slog.Error("http.NewRequest: " + err.Error()) + return false, err + } + + resp, err := c.client.Do(req) + if err != nil { + slog.Error("client.Do: " + err.Error()) + return false, err + } + if resp.StatusCode != http.StatusOK { + return false, errors.New("get failed: " + resp.Status) + } + response, err := io.ReadAll(resp.Body) + if err != nil { + slog.Error("io.ReadAll: " + err.Error()) + return false, err + } + var verifyTokenResponse api.VerifyTokenResponse + err = json.Unmarshal(response, &verifyTokenResponse) + if err != nil { + slog.Error("json.Unmarshal: " + err.Error()) + return false, err + } + return verifyTokenResponse.Verified, nil +} + +func (c *ClientAuth) post(path string, body map[string]any) ([]byte, error) { + bytesBody, _ := json.Marshal(body) + + resp, err := c.client.Post(c.baseURL+path, "application/json", bytes.NewReader(bytesBody)) + if err != nil { + slog.Error("c.client.Post: " + err.Error()) + return nil, err + + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, errors.New("tinkoff: post failed: " + resp.Status) + } + + response, err := io.ReadAll(resp.Body) + if err != nil { + slog.Error("io.ReadAll: " + err.Error()) + return nil, err + } + + return response, nil +}