mirror of
https://github.com/simon987/task_tracker.git
synced 2025-12-10 21:48:52 +00:00
Implement per-project webhook secret
This commit is contained in:
27
api/git.go
27
api/git.go
@@ -16,13 +16,6 @@ import (
|
||||
|
||||
func (api *WebAPI) ReceiveGitWebHook(r *Request) {
|
||||
|
||||
if !signatureValid(r) {
|
||||
logrus.Error("WebHook signature does not match!")
|
||||
r.Ctx.SetStatusCode(403)
|
||||
_, _ = fmt.Fprintf(r.Ctx, "Signature does not match")
|
||||
return
|
||||
}
|
||||
|
||||
payload := &GitPayload{}
|
||||
err := json.Unmarshal(r.Ctx.Request.Body(), payload)
|
||||
if err != nil {
|
||||
@@ -35,11 +28,27 @@ func (api *WebAPI) ReceiveGitWebHook(r *Request) {
|
||||
}).Info("Received git WebHook")
|
||||
|
||||
if !isProductionBranch(payload) {
|
||||
r.Ctx.SetStatusCode(400)
|
||||
return
|
||||
}
|
||||
|
||||
project := api.getAssociatedProject(payload)
|
||||
if project == nil {
|
||||
r.Ctx.SetStatusCode(400)
|
||||
return
|
||||
}
|
||||
|
||||
signature, err := api.Database.GetWebhookSecret(project.Id)
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(r.Ctx, err.Error())
|
||||
r.Ctx.SetStatusCode(400)
|
||||
return
|
||||
}
|
||||
|
||||
if !signatureValid(r, signature) {
|
||||
logrus.Error("WebHook signature does not match!")
|
||||
r.Ctx.SetStatusCode(403)
|
||||
_, _ = fmt.Fprintf(r.Ctx, "Signature does not match")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -50,7 +59,7 @@ func (api *WebAPI) ReceiveGitWebHook(r *Request) {
|
||||
handleErr(err, r)
|
||||
}
|
||||
|
||||
func signatureValid(r *Request) (matches bool) {
|
||||
func signatureValid(r *Request, webhookSignature string) (matches bool) {
|
||||
|
||||
signature := parseSignatureFromRequest(r.Ctx)
|
||||
|
||||
@@ -60,7 +69,7 @@ func signatureValid(r *Request) (matches bool) {
|
||||
|
||||
body := r.Ctx.PostBody()
|
||||
|
||||
mac := hmac.New(getHashFuncFromConfig(), config.Cfg.WebHookSecret)
|
||||
mac := hmac.New(getHashFuncFromConfig(), []byte(webhookSignature))
|
||||
mac.Write(body)
|
||||
|
||||
expectedMac := hex.EncodeToString(mac.Sum(nil))
|
||||
|
||||
@@ -93,6 +93,8 @@ func New() *WebAPI {
|
||||
api.router.POST("/project/reject_request/:id/:wid", LogRequestMiddleware(api.RejectAccessRequest))
|
||||
api.router.GET("/project/secret/:id", LogRequestMiddleware(api.GetSecret))
|
||||
api.router.POST("/project/secret/:id", LogRequestMiddleware(api.SetSecret))
|
||||
api.router.GET("/project/webhook_secret/:id", LogRequestMiddleware(api.GetWebhookSecret))
|
||||
api.router.POST("/project/webhook_secret/:id", LogRequestMiddleware(api.SetWebhookSecret))
|
||||
|
||||
api.router.POST("/task/submit", LogRequestMiddleware(api.SubmitTask))
|
||||
api.router.GET("/task/get/:project", LogRequestMiddleware(api.GetTaskFromProject))
|
||||
|
||||
@@ -292,3 +292,10 @@ type SetSecretRequest struct {
|
||||
type GetSecretResponse struct {
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
type SetWebhookSecretRequest struct {
|
||||
WebhookSecret string `json:"webhook_secret"`
|
||||
}
|
||||
type GetWebhookSecretResponse struct {
|
||||
WebhookSecret string `json:"webhook_secret"`
|
||||
}
|
||||
|
||||
101
api/project.go
101
api/project.go
@@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/google/uuid"
|
||||
"github.com/simon987/task_tracker/storage"
|
||||
"strconv"
|
||||
)
|
||||
@@ -97,7 +98,9 @@ func (api *WebAPI) CreateProject(r *Request) {
|
||||
return
|
||||
}
|
||||
|
||||
id, err := api.Database.SaveProject(project)
|
||||
webhookSecret := makeWebhookSecret()
|
||||
|
||||
id, err := api.Database.SaveProject(project, webhookSecret)
|
||||
if err != nil {
|
||||
r.Json(JsonResponse{
|
||||
Ok: false,
|
||||
@@ -107,7 +110,7 @@ func (api *WebAPI) CreateProject(r *Request) {
|
||||
}
|
||||
|
||||
api.Database.SetManagerRoleOn(manager.(*storage.Manager).Id, id,
|
||||
storage.ROLE_MANAGE_ACCESS|storage.ROLE_READ|storage.ROLE_EDIT)
|
||||
storage.RoleManageAccess|storage.RoleRead|storage.RoleEdit|storage.RoleSecret)
|
||||
r.OkJson(JsonResponse{
|
||||
Ok: true,
|
||||
Content: CreateProjectResponse{
|
||||
@@ -119,6 +122,10 @@ func (api *WebAPI) CreateProject(r *Request) {
|
||||
}).Debug("Created project")
|
||||
}
|
||||
|
||||
func makeWebhookSecret() string {
|
||||
return uuid.New().String()
|
||||
}
|
||||
|
||||
func (api *WebAPI) UpdateProject(r *Request) {
|
||||
|
||||
id, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
|
||||
@@ -163,7 +170,7 @@ func (api *WebAPI) UpdateProject(r *Request) {
|
||||
sess := api.Session.StartFasthttp(r.Ctx)
|
||||
manager := sess.Get("manager")
|
||||
|
||||
if !isActionOnProjectAuthorized(project.Id, manager, storage.ROLE_EDIT, api.Database) {
|
||||
if !isActionOnProjectAuthorized(project.Id, manager, storage.RoleEdit, api.Database) {
|
||||
r.Json(JsonResponse{
|
||||
Ok: false,
|
||||
Message: "Unauthorized",
|
||||
@@ -238,7 +245,7 @@ func isProjectReadAuthorized(project *storage.Project, manager interface{}, db *
|
||||
return true
|
||||
}
|
||||
role := db.GetManagerRoleOn(manager.(*storage.Manager), project.Id)
|
||||
if role&storage.ROLE_READ == 1 {
|
||||
if role&storage.RoleRead == 1 {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -302,7 +309,7 @@ func (api *WebAPI) GetWorkerAccessListForProject(r *Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if !isActionOnProjectAuthorized(id, manager, storage.ROLE_MANAGE_ACCESS, api.Database) {
|
||||
if !isActionOnProjectAuthorized(id, manager, storage.RoleManageAccess, api.Database) {
|
||||
r.Json(JsonResponse{
|
||||
Ok: false,
|
||||
Message: "Unauthorized",
|
||||
@@ -391,7 +398,7 @@ func (api *WebAPI) AcceptAccessRequest(r *Request) {
|
||||
sess := api.Session.StartFasthttp(r.Ctx)
|
||||
manager := sess.Get("manager")
|
||||
|
||||
if !isActionOnProjectAuthorized(pid, manager, storage.ROLE_MANAGE_ACCESS, api.Database) {
|
||||
if !isActionOnProjectAuthorized(pid, manager, storage.RoleManageAccess, api.Database) {
|
||||
r.Json(JsonResponse{
|
||||
Message: "Unauthorized",
|
||||
Ok: false,
|
||||
@@ -471,7 +478,7 @@ func (api *WebAPI) SetManagerRoleOnProject(r *Request) {
|
||||
sess := api.Session.StartFasthttp(r.Ctx)
|
||||
manager := sess.Get("manager")
|
||||
|
||||
if !isActionOnProjectAuthorized(pid, manager, storage.ROLE_MANAGE_ACCESS, api.Database) {
|
||||
if !isActionOnProjectAuthorized(pid, manager, storage.RoleManageAccess, api.Database) {
|
||||
r.Json(JsonResponse{
|
||||
Message: "Unauthorized",
|
||||
Ok: false,
|
||||
@@ -500,7 +507,7 @@ func (api *WebAPI) SetSecret(r *Request) {
|
||||
sess := api.Session.StartFasthttp(r.Ctx)
|
||||
manager := sess.Get("manager")
|
||||
|
||||
if !isActionOnProjectAuthorized(pid, manager, storage.ROLE_EDIT, api.Database) {
|
||||
if !isActionOnProjectAuthorized(pid, manager, storage.RoleSecret, api.Database) {
|
||||
r.Json(JsonResponse{
|
||||
Ok: false,
|
||||
Message: "Unauthorized",
|
||||
@@ -560,7 +567,7 @@ func (api *WebAPI) GetSecret(r *Request) {
|
||||
sess := api.Session.StartFasthttp(r.Ctx)
|
||||
manager := sess.Get("manager")
|
||||
|
||||
if !isActionOnProjectAuthorized(pid, manager, storage.ROLE_EDIT, api.Database) {
|
||||
if !isActionOnProjectAuthorized(pid, manager, storage.RoleSecret, api.Database) {
|
||||
r.Json(JsonResponse{
|
||||
Ok: false,
|
||||
Message: "Unauthorized",
|
||||
@@ -576,3 +583,79 @@ func (api *WebAPI) GetSecret(r *Request) {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (api *WebAPI) GetWebhookSecret(r *Request) {
|
||||
|
||||
pid, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
|
||||
if err != nil || pid <= 0 {
|
||||
r.Json(JsonResponse{
|
||||
Ok: false,
|
||||
Message: "Invalid project id",
|
||||
}, 400)
|
||||
return
|
||||
}
|
||||
|
||||
sess := api.Session.StartFasthttp(r.Ctx)
|
||||
manager := sess.Get("manager")
|
||||
|
||||
if !isActionOnProjectAuthorized(pid, manager, storage.RoleSecret, api.Database) {
|
||||
r.Json(JsonResponse{
|
||||
Ok: false,
|
||||
Message: "Unauthorized",
|
||||
}, 403)
|
||||
return
|
||||
}
|
||||
|
||||
secret, err := api.Database.GetWebhookSecret(pid)
|
||||
r.OkJson(JsonResponse{
|
||||
Ok: true,
|
||||
Content: GetWebhookSecretResponse{
|
||||
WebhookSecret: secret,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (api *WebAPI) SetWebhookSecret(r *Request) {
|
||||
|
||||
pid, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
|
||||
if err != nil || pid <= 0 {
|
||||
r.Json(JsonResponse{
|
||||
Ok: false,
|
||||
Message: "Invalid project id",
|
||||
}, 400)
|
||||
return
|
||||
}
|
||||
|
||||
req := &SetWebhookSecretRequest{}
|
||||
err = json.Unmarshal(r.Ctx.Request.Body(), req)
|
||||
if err != nil {
|
||||
r.Json(JsonResponse{
|
||||
Ok: false,
|
||||
Message: "Could not parse request",
|
||||
}, 400)
|
||||
return
|
||||
}
|
||||
|
||||
sess := api.Session.StartFasthttp(r.Ctx)
|
||||
manager := sess.Get("manager")
|
||||
|
||||
if !isActionOnProjectAuthorized(pid, manager, storage.RoleSecret, api.Database) {
|
||||
r.Json(JsonResponse{
|
||||
Ok: false,
|
||||
Message: "Unauthorized",
|
||||
}, 403)
|
||||
return
|
||||
}
|
||||
|
||||
err = api.Database.SetWebhookSecret(pid, req.WebhookSecret)
|
||||
if err == nil {
|
||||
r.OkJson(JsonResponse{
|
||||
Ok: true,
|
||||
})
|
||||
} else {
|
||||
r.OkJson(JsonResponse{
|
||||
Ok: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user