Compare commits

..

3 Commits

Author SHA1 Message Date
Elias Schneider
6e44b5e367 release: 0.26.0 2025-01-20 11:23:52 +01:00
Elias Schneider
8a1db0cb4a feat: support wildcard callback URLs 2025-01-20 11:19:23 +01:00
Elias Schneider
3f02d08109 fix: non LDAP users get created with a empty LDAP ID string 2025-01-20 10:41:01 +01:00
14 changed files with 43 additions and 28 deletions

View File

@@ -1 +1 @@
0.25.1
0.26.0

View File

@@ -1,3 +1,15 @@
## [](https://github.com/stonith404/pocket-id/compare/v0.25.1...v) (2025-01-20)
### Features
* support wildcard callback URLs ([8a1db0c](https://github.com/stonith404/pocket-id/commit/8a1db0cb4a5d4b32b4fdc19d41fff688a7c71a56))
### Bug Fixes
* non LDAP users get created with a empty LDAP ID string ([3f02d08](https://github.com/stonith404/pocket-id/commit/3f02d081098ad2caaa60a56eea4705639f80d01f))
## [](https://github.com/stonith404/pocket-id/compare/v0.25.0...v) (2025-01-19)

View File

@@ -16,7 +16,7 @@ type OidcClientDto struct {
type OidcClientCreateDto struct {
Name string `json:"name" binding:"required,max=50"`
CallbackURLs []string `json:"callbackURLs" binding:"required,urlList"`
CallbackURLs []string `json:"callbackURLs" binding:"required"`
IsPublic bool `json:"isPublic"`
PkceEnabled bool `json:"pkceEnabled"`
}

View File

@@ -4,21 +4,9 @@ import (
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
"log"
"net/url"
"regexp"
)
var validateUrlList validator.Func = func(fl validator.FieldLevel) bool {
urls := fl.Field().Interface().([]string)
for _, u := range urls {
_, err := url.ParseRequestURI(u)
if err != nil {
return false
}
}
return true
}
var validateUsername validator.Func = func(fl validator.FieldLevel) bool {
// [a-zA-Z0-9] : The username must start with an alphanumeric character
// [a-zA-Z0-9_.@-]* : The rest of the username can contain alphanumeric characters, dots, underscores, hyphens, and "@" symbols
@@ -36,11 +24,6 @@ var validateClaimKey validator.Func = func(fl validator.FieldLevel) bool {
}
func init() {
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
if err := v.RegisterValidation("urlList", validateUrlList); err != nil {
log.Fatalf("Failed to register custom validation: %v", err)
}
}
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
if err := v.RegisterValidation("username", validateUsername); err != nil {
log.Fatalf("Failed to register custom validation: %v", err)

View File

@@ -83,8 +83,6 @@ func handleValidationError(validationErrors validator.ValidationErrors) string {
errorMessage = fmt.Sprintf("%s must be at least %s characters long", fieldName, ve.Param())
case "max":
errorMessage = fmt.Sprintf("%s must be at most %s characters long", fieldName, ve.Param())
case "urlList":
errorMessage = fmt.Sprintf("%s must be a list of valid URLs", fieldName)
default:
errorMessage = fmt.Sprintf("%s is invalid", fieldName)
}

View File

@@ -14,7 +14,7 @@ import (
"gorm.io/gorm"
"mime/multipart"
"os"
"slices"
"regexp"
"strings"
"time"
)
@@ -432,8 +432,16 @@ func (s *OidcService) getCallbackURL(client model.OidcClient, inputCallbackURL s
if inputCallbackURL == "" {
return client.CallbackURLs[0], nil
}
if slices.Contains(client.CallbackURLs, inputCallbackURL) {
return inputCallbackURL, nil
for _, callbackPattern := range client.CallbackURLs {
regexPattern := strings.ReplaceAll(regexp.QuoteMeta(callbackPattern), `\*`, ".*") + "$"
matched, err := regexp.MatchString(regexPattern, inputCallbackURL)
if err != nil {
return "", err
}
if matched {
return inputCallbackURL, nil
}
}
return "", &common.OidcInvalidCallbackURLError{}

View File

@@ -62,7 +62,10 @@ func (s *UserGroupService) Create(input dto.UserGroupCreateDto) (group model.Use
group = model.UserGroup{
FriendlyName: input.FriendlyName,
Name: input.Name,
LdapID: &input.LdapID,
}
if input.LdapID != "" {
group.LdapID = &input.LdapID
}
if err := s.db.Preload("Users").Create(&group).Error; err != nil {

View File

@@ -66,8 +66,11 @@ func (s *UserService) CreateUser(input dto.UserCreateDto) (model.User, error) {
Email: input.Email,
Username: input.Username,
IsAdmin: input.IsAdmin,
LdapID: &input.LdapID,
}
if input.LdapID != "" {
user.LdapID = &input.LdapID
}
if err := s.db.Create(&user).Error; err != nil {
if errors.Is(err, gorm.ErrDuplicatedKey) {
return model.User{}, s.checkDuplicatedFields(user)

View File

@@ -0,0 +1,2 @@
UPDATE users SET ldap_id = '' WHERE ldap_id IS NULL;
UPDATE user_groups SET ldap_id = '' WHERE ldap_id IS NULL;

View File

@@ -0,0 +1,2 @@
UPDATE users SET ldap_id = null WHERE ldap_id = '';
UPDATE user_groups SET ldap_id = null WHERE ldap_id = '';

View File

@@ -0,0 +1,2 @@
UPDATE users SET ldap_id = '' WHERE ldap_id IS NULL;
UPDATE user_groups SET ldap_id = '' WHERE ldap_id IS NULL;

View File

@@ -0,0 +1,2 @@
UPDATE users SET ldap_id = null WHERE ldap_id = '';
UPDATE user_groups SET ldap_id = null WHERE ldap_id = '';

View File

@@ -1,6 +1,6 @@
{
"name": "pocket-id-frontend",
"version": "0.25.1",
"version": "0.26.0",
"private": true,
"scripts": {
"dev": "vite dev --port 3000",

View File

@@ -36,7 +36,7 @@
const formSchema = z.object({
name: z.string().min(2).max(50),
callbackURLs: z.array(z.string().url()).nonempty(),
callbackURLs: z.array(z.string()).nonempty(),
isPublic: z.boolean(),
pkceEnabled: z.boolean()
});