init from gitlab
This commit is contained in:
101
internal/server/api/setup/password.go
Normal file
101
internal/server/api/setup/password.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/rs/zerolog/log"
|
||||
"gitlab.com/texm/shokku/internal/models"
|
||||
"gitlab.com/texm/shokku/internal/server/auth"
|
||||
"image/png"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/pquerna/otp/totp"
|
||||
"gitlab.com/texm/shokku/internal/env"
|
||||
"gitlab.com/texm/shokku/internal/server/dto"
|
||||
)
|
||||
|
||||
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
|
||||
func generateRandomString(n int) string {
|
||||
b := make([]rune, n)
|
||||
for i := range b {
|
||||
b[i] = letterRunes[rand.Intn(len(letterRunes))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func GenerateTotp(e *env.Env, c echo.Context) error {
|
||||
key, err := totp.Generate(totp.GenerateOpts{
|
||||
Issuer: "shokku",
|
||||
AccountName: "admin account",
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate totp key: %w", err)
|
||||
}
|
||||
|
||||
var imgBuf bytes.Buffer
|
||||
img, imgErr := key.Image(160, 160)
|
||||
if imgErr != nil {
|
||||
return fmt.Errorf("failed to generate totp image: %w", imgErr)
|
||||
}
|
||||
if encErr := png.Encode(&imgBuf, img); encErr != nil {
|
||||
return fmt.Errorf("failed to encode totp image to png: %w", encErr)
|
||||
}
|
||||
return c.JSON(http.StatusOK, dto.GenerateTotpResponse{
|
||||
Secret: key.Secret(),
|
||||
Image: base64.StdEncoding.EncodeToString(imgBuf.Bytes()),
|
||||
RecoveryCode: generateRandomString(12),
|
||||
})
|
||||
}
|
||||
|
||||
func ConfirmTotp(e *env.Env, c echo.Context) error {
|
||||
var req dto.ConfirmTotpRequest
|
||||
if err := dto.BindRequest(c, &req); err != nil {
|
||||
return err.ToHTTP()
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, dto.ConfirmTotpResponse{
|
||||
Valid: totp.Validate(req.Code, req.Secret),
|
||||
})
|
||||
}
|
||||
|
||||
func CompletePasswordSetup(e *env.Env, c echo.Context) error {
|
||||
var req dto.CompletePasswordSetupRequest
|
||||
if err := dto.BindRequest(c, &req); err != nil {
|
||||
return err.ToHTTP()
|
||||
}
|
||||
|
||||
if err := setupServerWithAuthMethod(e, auth.MethodPassword); err != nil {
|
||||
log.Error().Err(err).Msg("failed to setup github auth")
|
||||
return echo.ErrInternalServerError
|
||||
}
|
||||
|
||||
pw, ok := e.Auth.(*auth.PasswordAuthenticator)
|
||||
if !ok {
|
||||
log.Error().Msg("failed to cast e.Auth to pw auth")
|
||||
return echo.ErrInternalServerError
|
||||
}
|
||||
passwordHash, pwErr := pw.HashPassword([]byte(req.Password))
|
||||
if pwErr != nil {
|
||||
log.Error().Err(pwErr).Msg("failed to hash password")
|
||||
return echo.ErrInternalServerError
|
||||
}
|
||||
|
||||
user := models.User{
|
||||
Name: req.Username,
|
||||
Source: "manual",
|
||||
PasswordHash: passwordHash,
|
||||
TotpEnabled: req.Enable2FA,
|
||||
RecoveryCode: req.RecoveryCode,
|
||||
TotpSecret: req.TotpSecret,
|
||||
}
|
||||
if err := e.DB.Save(&user).Error; err != nil {
|
||||
log.Error().Err(err).Msg("failed to save initial password auth user")
|
||||
return echo.ErrInternalServerError
|
||||
}
|
||||
|
||||
return c.NoContent(http.StatusOK)
|
||||
}
|
||||
Reference in New Issue
Block a user