Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 3 additions & 3 deletions .air.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ tmp_dir = "tmp"
[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ./cmd/main.go"
cmd = "go build -o ./tmp/main ./cmd/"
delay = 1000
entrypoint = ["./tmp/main"]
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
Expand All @@ -19,15 +19,15 @@ tmp_dir = "tmp"
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html", "yaml"]
include_file = []
kill_delay = "0s"
kill_delay = "1s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
send_interrupt = true
stop_on_error = true

[color]
Expand Down
15 changes: 15 additions & 0 deletions api/dto/secret.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dto

type SecretInput struct {
Name string `json:"name"`
Value string `json:"value"`
}

type Secret struct {
Name string `json:"name"`
Value string `json:"-"`
}

type SecretFilter struct {
Name string
}
5 changes: 5 additions & 0 deletions api/dto/auth.go → api/dto/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ type LoginInput struct {
Email string `json:"email" form:"email" binding:"required,email"`
Password string `json:"password" form:"password" binding:"required"`
}

type UserFilter struct {
Email string
IsActive *bool
}
6 changes: 2 additions & 4 deletions api/http/apiutils/user-role.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ package apiutils
type Role string

const (
RoleAdmin Role = "admin"
RoleEmployee Role = "employee"
RoleUser Role = "user"
RoleAdmin Role = "admin"
)

func (r Role) ValidRole() (Role, bool) {
valid := false
switch r {
case RoleAdmin, RoleEmployee, RoleUser:
case RoleAdmin:
valid = true
}
return r, valid
Expand Down
60 changes: 0 additions & 60 deletions api/http/controllers/admin.go

This file was deleted.

29 changes: 29 additions & 0 deletions api/http/controllers/api-key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package controllers

import (
"fmt"

"github.com/gin-gonic/gin"
)

func (h *Handler) CreateAPIKey(c *gin.Context) {

// [TODO] create api key and display it only ONCE (alias -> unique identifier)

h.response.Created(c, "New API Key Created", nil)
}

func (h *Handler) ListAllAPIKeys(c *gin.Context) {

// [TODO] display aliases and other metadata of api keys (NEVER the actual key)

h.response.Success(c, "All API Keys", nil)
}

func (h *Handler) DeleteAPIKey(c *gin.Context) {
key := c.Param("key")

// [TODO] delete an api key through given alias

h.response.Success(c, fmt.Sprintf("Key Deleted - %v", key), nil)
}
62 changes: 54 additions & 8 deletions api/http/controllers/auth.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
package controllers

import (
"crypto/subtle"
"errors"
"fmt"

"github.com/gin-gonic/gin"
"github.com/kunalvirwal/shogun-cd/api/dto"
"github.com/kunalvirwal/shogun-cd/api/http/apiutils"
"github.com/kunalvirwal/shogun-cd/internal/store"
"golang.org/x/crypto/bcrypt"
)

func (h *Handler) Register(c *gin.Context) {
var req dto.LoginInput

if err := c.ShouldBind(&req); err != nil {
h.response.BadRequest(c, "Bad Input", err)
return
}
ctx := c.Request.Context()
err := h.store.User.Create(ctx, &req)
if err != nil {
switch {
case errors.Is(err, store.ErrEmailTaken):
h.response.BadRequest(c, store.ErrEmailTaken.Error(), err)
return

default:
h.response.ServerError(c, err)
return
}
}

h.response.Success(c, fmt.Sprintf("registered new user - %v", req.Email), nil)
}

func (h *Handler) Login(c *gin.Context) {
var req dto.LoginInput

Expand All @@ -17,16 +43,36 @@ func (h *Handler) Login(c *gin.Context) {
return
}

//[TODO] multi user support through DB lookup
validEmail := subtle.ConstantTimeCompare([]byte(req.Email), []byte(h.config.ApiConfig.Admin.Email)) == 1
validPassword := subtle.ConstantTimeCompare([]byte(req.Password), []byte(h.config.ApiConfig.Admin.Password)) == 1
if !validEmail || !validPassword {
h.response.Unauthorized(c, "Invalid Email or Password", nil)
user, err := h.store.User.FindOne(c.Request.Context(), &dto.UserFilter{
Email: req.Email,
})
if err != nil {
switch {
case errors.Is(err, store.ErrRecordNotFound):
h.response.Unauthorized(c, "Invalid email or password", err)
return
default:
h.response.ServerError(c, err)
return
}
}

if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil {
switch {
case errors.Is(err, bcrypt.ErrMismatchedHashAndPassword):
h.response.Unauthorized(c, "Invalid email or password", err)
return
default:
h.response.ServerError(c, err)
return
}
}
if !*user.IsActive {
h.response.Forbidden(c, "This Account is Suspended", store.ErrAccountSuspended)
return
}

//[TODO] DB call to get the user's role to be embedded in jwt.
role := apiutils.RoleAdmin
role := apiutils.Role(user.Role)
secret := h.config.ApiConfig.JWT.Secret
exp := h.config.ApiConfig.JWT.ExpirationHours

Expand Down
8 changes: 7 additions & 1 deletion api/http/controllers/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package controllers
import (
"github.com/kunalvirwal/shogun-cd/api/http/response"
"github.com/kunalvirwal/shogun-cd/internal/config"
"github.com/kunalvirwal/shogun-cd/internal/secrets"
"github.com/kunalvirwal/shogun-cd/internal/store"
"github.com/kunalvirwal/shogun-cd/internal/utils"
"github.com/kunalvirwal/shogun-cd/internal/webhooks"
)
Expand All @@ -12,13 +14,17 @@ type Handler struct {
config *config.Config
response response.Responder
webhook webhooks.WebhookService
store *store.Store
secret secrets.SecretService
}

func NewHandler(l utils.Logger, cfg *config.Config, responder response.Responder, wh webhooks.WebhookService) *Handler {
func NewHandler(l utils.Logger, cfg *config.Config, responder response.Responder, wh webhooks.WebhookService, store *store.Store, secrets secrets.SecretService) *Handler {
return &Handler{
logger: l,
config: cfg,
response: responder,
webhook: wh,
store: store,
secret: secrets,
}
}
52 changes: 52 additions & 0 deletions api/http/controllers/secret.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package controllers

import (
"fmt"

"github.com/gin-gonic/gin"
"github.com/kunalvirwal/shogun-cd/api/dto"
)

func (h *Handler) ListAllSecrets(c *gin.Context) {
var req dto.SecretFilter

if err := c.ShouldBind(&req); err != nil {
h.response.BadRequest(c, "Bad Input", err)
return
}

data, err := h.secret.FindMany(c.Request.Context(), &req)
if err != nil {
h.response.ServerError(c, err)
return
}

h.response.Success(c, "All Secrets (names only)", data)
}

func (h *Handler) SetSecrets(c *gin.Context) {
var req []dto.SecretInput

if err := c.ShouldBindJSON(&req); err != nil {
h.response.BadRequest(c, "Bad Input", err)
return
}

if err := h.secret.SetSecrets(c.Request.Context(), req); err != nil {
h.response.ServerError(c, err)
return
}

h.response.Created(c, "New Secret(s) Created", nil)
}

func (h *Handler) DeleteSecret(c *gin.Context) {
s := c.Param("secret")

if err := h.secret.DeleteSecret(c.Request.Context(), s); err != nil {
h.response.ServerError(c, err)
return
}

h.response.Success(c, fmt.Sprintf("Secret Deleted - %v", s), nil)
}
Loading