Create deploy token on site creation
This commit is contained in:
+17
-2
@@ -6,6 +6,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"quay/app/models"
|
"quay/app/models"
|
||||||
"quay/app/repository"
|
"quay/app/repository"
|
||||||
|
"quay/internal/security"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
)
|
)
|
||||||
@@ -145,7 +146,7 @@ func validateIncomingSite(site *models.Site) error {
|
|||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param site body models.Site true "Site details"
|
// @Param site body models.Site true "Site details"
|
||||||
// @Success 200 {object} models.Site
|
// @Success 200 {object} models.CreateSiteResponse
|
||||||
// @Failure 400 {object} models.APIError
|
// @Failure 400 {object} models.APIError
|
||||||
// @Failure 500 {object} models.APIError
|
// @Failure 500 {object} models.APIError
|
||||||
// @Router /sites [post]
|
// @Router /sites [post]
|
||||||
@@ -165,6 +166,17 @@ func (h *SiteHandler) PostSite(c fiber.Ctx) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rawDeployToken, hashedDeployToken, err := security.CreateDeployToken()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error creating deploy token: ", err)
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(&models.APIError{
|
||||||
|
Message: "Unexpected error while creating deploy token: " + err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
site.DeployToken = hashedDeployToken
|
||||||
|
|
||||||
if err := h.Repo.CreateSite(&site); err != nil {
|
if err := h.Repo.CreateSite(&site); err != nil {
|
||||||
log.Println("Error creating site: ", err)
|
log.Println("Error creating site: ", err)
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(&models.APIError{
|
return c.Status(fiber.StatusInternalServerError).JSON(&models.APIError{
|
||||||
@@ -172,7 +184,10 @@ func (h *SiteHandler) PostSite(c fiber.Ctx) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.JSON(site)
|
return c.JSON(&models.CreateSiteResponse{
|
||||||
|
Site: site,
|
||||||
|
RawDeployToken: rawDeployToken,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutSite godoc
|
// PutSite godoc
|
||||||
|
|||||||
@@ -39,3 +39,8 @@ type GetAllSitesResponse struct {
|
|||||||
Sites []Site `json:"sites"`
|
Sites []Site `json:"sites"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateSiteResponse struct {
|
||||||
|
Site Site `json:"site"`
|
||||||
|
RawDeployToken string `json:"raw_deploy_token"`
|
||||||
|
}
|
||||||
|
|||||||
+12
-1
@@ -573,7 +573,7 @@ const docTemplate = `{
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/models.Site"
|
"$ref": "#/definitions/models.CreateSiteResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
@@ -943,6 +943,17 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"models.CreateSiteResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"raw_deploy_token": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"site": {
|
||||||
|
"$ref": "#/definitions/models.Site"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"models.CustomHeaders": {
|
"models.CustomHeaders": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
+12
-1
@@ -567,7 +567,7 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/models.Site"
|
"$ref": "#/definitions/models.CreateSiteResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
@@ -937,6 +937,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"models.CreateSiteResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"raw_deploy_token": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"site": {
|
||||||
|
"$ref": "#/definitions/models.Site"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"models.CustomHeaders": {
|
"models.CustomHeaders": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
+8
-1
@@ -5,6 +5,13 @@ definitions:
|
|||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
models.CreateSiteResponse:
|
||||||
|
properties:
|
||||||
|
raw_deploy_token:
|
||||||
|
type: string
|
||||||
|
site:
|
||||||
|
$ref: '#/definitions/models.Site'
|
||||||
|
type: object
|
||||||
models.CustomHeaders:
|
models.CustomHeaders:
|
||||||
properties:
|
properties:
|
||||||
headers:
|
headers:
|
||||||
@@ -456,7 +463,7 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/models.Site'
|
$ref: '#/definitions/models.CreateSiteResponse'
|
||||||
"400":
|
"400":
|
||||||
description: Bad Request
|
description: Bad Request
|
||||||
schema:
|
schema:
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package security
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/subtle"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func generateToken() (rawToken string, err error) {
|
||||||
|
bytes := make([]byte, 32)
|
||||||
|
if _, err = rand.Read(bytes); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return "quay_" + hex.EncodeToString(bytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hashToken(rawToken string) string {
|
||||||
|
sum := sha256.Sum256([]byte(rawToken))
|
||||||
|
return hex.EncodeToString(sum[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateDeployToken() (rawToken, hashedToken string, err error) {
|
||||||
|
rawToken, err = generateToken()
|
||||||
|
if err != nil {
|
||||||
|
return "", "", fmt.Errorf("failed to generate token: %w", err)
|
||||||
|
}
|
||||||
|
hashedToken = hashToken(rawToken)
|
||||||
|
return rawToken, hashedToken, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompareDeployTokens(incomingRawToken, storedHashedToken string) bool {
|
||||||
|
incomingHash := hashToken(incomingRawToken)
|
||||||
|
|
||||||
|
return subtle.ConstantTimeCompare(
|
||||||
|
[]byte(incomingHash),
|
||||||
|
[]byte(storedHashedToken),
|
||||||
|
) == 1
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user