mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2025-12-07 07:42:45 +01:00
Remove user passwords (#539)
* Remove user passwords Co-authored-by: Jonas Plum <git@jonasplum.de>
This commit is contained in:
9
auth.go
9
auth.go
@@ -33,11 +33,10 @@ func (c *catalystResolver) UserCreateIfNotExists(ctx context.Context, user *maut
|
|||||||
_, err = c.database.UserCreateSetupAPIKey(ctx, password)
|
_, err = c.database.UserCreateSetupAPIKey(ctx, password)
|
||||||
} else {
|
} else {
|
||||||
_, err = c.database.UserCreate(ctx, &model.UserForm{
|
_, err = c.database.UserCreate(ctx, &model.UserForm{
|
||||||
Apikey: user.APIKey,
|
Apikey: user.APIKey,
|
||||||
Blocked: user.Blocked,
|
Blocked: user.Blocked,
|
||||||
ID: user.ID,
|
ID: user.ID,
|
||||||
Password: &password,
|
Roles: user.Roles,
|
||||||
Roles: user.Roles,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -41,20 +41,20 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = theCatalyst.DB.UserCreate(context.Background(), &model.UserForm{ID: "eve", Roles: []string{"admin"}, Password: pointer.String("eve")})
|
_, _ = theCatalyst.DB.UserCreate(context.Background(), &model.UserForm{ID: "eve", Roles: []string{"admin"}})
|
||||||
_ = theCatalyst.DB.UserDataCreate(context.Background(), "eve", &model.UserData{
|
_ = theCatalyst.DB.UserDataCreate(context.Background(), "eve", &model.UserData{
|
||||||
Name: pointer.String("Eve"),
|
Name: pointer.String("Eve"),
|
||||||
Email: pointer.String("eve@example.com"),
|
Email: pointer.String("eve@example.com"),
|
||||||
Image: &avatarEve,
|
Image: &avatarEve,
|
||||||
})
|
})
|
||||||
_, _ = theCatalyst.DB.UserCreate(context.Background(), &model.UserForm{ID: "kevin", Roles: []string{"admin"}, Password: pointer.String("kevin")})
|
_, _ = theCatalyst.DB.UserCreate(context.Background(), &model.UserForm{ID: "kevin", Roles: []string{"admin"}})
|
||||||
_ = theCatalyst.DB.UserDataCreate(context.Background(), "kevin", &model.UserData{
|
_ = theCatalyst.DB.UserDataCreate(context.Background(), "kevin", &model.UserData{
|
||||||
Name: pointer.String("Kevin"),
|
Name: pointer.String("Kevin"),
|
||||||
Email: pointer.String("kevin@example.com"),
|
Email: pointer.String("kevin@example.com"),
|
||||||
Image: &avatarKevin,
|
Image: &avatarKevin,
|
||||||
})
|
})
|
||||||
|
|
||||||
_, _ = theCatalyst.DB.UserCreate(context.Background(), &model.UserForm{ID: "tom", Roles: []string{"admin"}, Password: pointer.String("tom")})
|
_, _ = theCatalyst.DB.UserCreate(context.Background(), &model.UserForm{ID: "tom", Roles: []string{"admin"}})
|
||||||
_ = theCatalyst.DB.UserDataCreate(context.Background(), "tom", &model.UserData{
|
_ = theCatalyst.DB.UserDataCreate(context.Background(), "tom", &model.UserData{
|
||||||
Name: pointer.String("tom"),
|
Name: pointer.String("tom"),
|
||||||
Email: pointer.String("tom@example.com"),
|
Email: pointer.String("tom@example.com"),
|
||||||
|
|||||||
@@ -61,8 +61,6 @@ func generateMigrations() ([]Migration, error) {
|
|||||||
|
|
||||||
&updateDocument[model.Settings]{ID: "update-settings-global-1", Collection: "settings", Key: "global", Document: &model.Settings{ArtifactStates: []*model.Type{{Icon: "mdi-help-circle-outline", ID: "unknown", Name: "Unknown", Color: pointer.String(model.TypeColorInfo)}, {Icon: "mdi-skull", ID: "malicious", Name: "Malicious", Color: pointer.String(model.TypeColorError)}, {Icon: "mdi-check", ID: "clean", Name: "Clean", Color: pointer.String(model.TypeColorSuccess)}}, ArtifactKinds: []*model.Type{{Icon: "mdi-server", ID: "asset", Name: "Asset"}, {Icon: "mdi-bullseye", ID: "ioc", Name: "IOC"}}, Timeformat: "yyyy-MM-dd hh:mm:ss"}},
|
&updateDocument[model.Settings]{ID: "update-settings-global-1", Collection: "settings", Key: "global", Document: &model.Settings{ArtifactStates: []*model.Type{{Icon: "mdi-help-circle-outline", ID: "unknown", Name: "Unknown", Color: pointer.String(model.TypeColorInfo)}, {Icon: "mdi-skull", ID: "malicious", Name: "Malicious", Color: pointer.String(model.TypeColorError)}, {Icon: "mdi-check", ID: "clean", Name: "Clean", Color: pointer.String(model.TypeColorSuccess)}}, ArtifactKinds: []*model.Type{{Icon: "mdi-server", ID: "asset", Name: "Asset"}, {Icon: "mdi-bullseye", ID: "ioc", Name: "IOC"}}, Timeformat: "yyyy-MM-dd hh:mm:ss"}},
|
||||||
|
|
||||||
&updateSchema{ID: "update-user-simple-login", Name: "users", DataType: "user", Schema: `{"type":"object","properties":{"apikey":{"type":"boolean"},"blocked":{"type":"boolean"},"roles":{"items":{"type":"string"},"type":"array"},"salt":{"type":"string"},"sha256":{"type":"string"},"sha512":{"type":"string"}},"required":["blocked","apikey","roles"],"$id":"#/definitions/User"}`},
|
|
||||||
|
|
||||||
&mapRoles{ID: "simplify-roles"},
|
&mapRoles{ID: "simplify-roles"},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package database
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/sha512"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
@@ -34,13 +33,11 @@ func generateKey() string {
|
|||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func toUser(user *model.UserForm, salt, sha256, sha512 *string) *model.User {
|
func toUser(user *model.UserForm, sha256 *string) *model.User {
|
||||||
u := &model.User{
|
u := &model.User{
|
||||||
Blocked: user.Blocked,
|
Blocked: user.Blocked,
|
||||||
Roles: user.Roles,
|
Roles: user.Roles,
|
||||||
Salt: salt,
|
|
||||||
Sha256: sha256,
|
Sha256: sha256,
|
||||||
Sha512: sha512,
|
|
||||||
Apikey: user.Apikey,
|
Apikey: user.Apikey,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,16 +86,14 @@ func (db *Database) UserGetOrCreate(ctx context.Context, newUser *model.UserForm
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) UserCreate(ctx context.Context, newUser *model.UserForm) (*model.NewUserResponse, error) {
|
func (db *Database) UserCreate(ctx context.Context, newUser *model.UserForm) (*model.NewUserResponse, error) {
|
||||||
var key, salt, sha256Hash, sha512Hash *string
|
var key, sha256Hash *string
|
||||||
if newUser.Apikey {
|
if newUser.Apikey {
|
||||||
key, sha256Hash = generateAPIKey()
|
key, sha256Hash = generateAPIKey()
|
||||||
} else if newUser.Password != nil {
|
|
||||||
salt, sha512Hash = hashUserPassword(newUser)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var doc model.User
|
var doc model.User
|
||||||
newctx := driver.WithReturnNew(ctx, &doc)
|
newctx := driver.WithReturnNew(ctx, &doc)
|
||||||
meta, err := db.userCollection.CreateDocument(ctx, newctx, strcase.ToKebab(newUser.ID), toUser(newUser, salt, sha256Hash, sha512Hash))
|
meta, err := db.userCollection.CreateDocument(ctx, newctx, strcase.ToKebab(newUser.ID), toUser(newUser, sha256Hash))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -117,7 +112,7 @@ func (db *Database) UserCreateSetupAPIKey(ctx context.Context, key string) (*mod
|
|||||||
|
|
||||||
var doc model.User
|
var doc model.User
|
||||||
newctx := driver.WithReturnNew(ctx, &doc)
|
newctx := driver.WithReturnNew(ctx, &doc)
|
||||||
meta, err := db.userCollection.CreateDocument(ctx, newctx, strcase.ToKebab(newUser.ID), toUser(newUser, nil, sha256Hash, nil))
|
meta, err := db.userCollection.CreateDocument(ctx, newctx, strcase.ToKebab(newUser.ID), toUser(newUser, sha256Hash))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -136,19 +131,11 @@ func (db *Database) UserUpdate(ctx context.Context, id string, user *model.UserF
|
|||||||
return nil, errors.New("cannot update an API key")
|
return nil, errors.New("cannot update an API key")
|
||||||
}
|
}
|
||||||
|
|
||||||
var salt, sha512Hash *string
|
|
||||||
if user.Password != nil {
|
|
||||||
salt, sha512Hash = hashUserPassword(user)
|
|
||||||
} else {
|
|
||||||
salt = doc.Salt
|
|
||||||
sha512Hash = doc.Sha512
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = driver.WithReturnNew(ctx, &doc)
|
ctx = driver.WithReturnNew(ctx, &doc)
|
||||||
|
|
||||||
user.ID = id
|
user.ID = id
|
||||||
|
|
||||||
meta, err := db.userCollection.ReplaceDocument(ctx, id, toUser(user, salt, nil, sha512Hash))
|
meta, err := db.userCollection.ReplaceDocument(ctx, id, toUser(user, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -244,13 +231,3 @@ func generateAPIKey() (key, sha256Hash *string) {
|
|||||||
|
|
||||||
return &newKey, sha256Hash
|
return &newKey, sha256Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashUserPassword(newUser *model.UserForm) (salt, sha512Hash *string) {
|
|
||||||
if newUser.Password != nil {
|
|
||||||
saltKey := generateKey()
|
|
||||||
salt = &saltKey
|
|
||||||
sha512Hash = pointer.String(fmt.Sprintf("%x", sha512.Sum512([]byte(saltKey+*newUser.Password))))
|
|
||||||
}
|
|
||||||
|
|
||||||
return salt, sha512Hash
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ definitions:
|
|||||||
required: [ id, blocked, roles, apikey ]
|
required: [ id, blocked, roles, apikey ]
|
||||||
properties:
|
properties:
|
||||||
id: { type: string }
|
id: { type: string }
|
||||||
password: { type: string }
|
|
||||||
blocked: { type: boolean }
|
blocked: { type: boolean }
|
||||||
apikey: { type: boolean }
|
apikey: { type: boolean }
|
||||||
roles: { type: array, items: { type: string } }
|
roles: { type: array, items: { type: string } }
|
||||||
@@ -102,9 +101,7 @@ definitions:
|
|||||||
blocked: { type: boolean }
|
blocked: { type: boolean }
|
||||||
apikey: { type: boolean }
|
apikey: { type: boolean }
|
||||||
roles: { type: array, items: { type: string } }
|
roles: { type: array, items: { type: string } }
|
||||||
salt: { type: string }
|
|
||||||
sha256: { type: string } # for api keys
|
sha256: { type: string } # for api keys
|
||||||
sha512: { type: string } # for users
|
|
||||||
|
|
||||||
UserResponse:
|
UserResponse:
|
||||||
type: object
|
type: object
|
||||||
|
|||||||
@@ -7102,14 +7102,8 @@
|
|||||||
},
|
},
|
||||||
"type" : "array"
|
"type" : "array"
|
||||||
},
|
},
|
||||||
"salt" : {
|
|
||||||
"type" : "string"
|
|
||||||
},
|
|
||||||
"sha256" : {
|
"sha256" : {
|
||||||
"type" : "string"
|
"type" : "string"
|
||||||
},
|
|
||||||
"sha512" : {
|
|
||||||
"type" : "string"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required" : [ "apikey", "blocked", "roles" ],
|
"required" : [ "apikey", "blocked", "roles" ],
|
||||||
@@ -7168,9 +7162,6 @@
|
|||||||
"id" : {
|
"id" : {
|
||||||
"type" : "string"
|
"type" : "string"
|
||||||
},
|
},
|
||||||
"password" : {
|
|
||||||
"type" : "string"
|
|
||||||
},
|
|
||||||
"roles" : {
|
"roles" : {
|
||||||
"items" : {
|
"items" : {
|
||||||
"type" : "string"
|
"type" : "string"
|
||||||
|
|||||||
@@ -1285,12 +1285,8 @@ definitions:
|
|||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
salt:
|
|
||||||
type: string
|
|
||||||
sha256:
|
sha256:
|
||||||
type: string
|
type: string
|
||||||
sha512:
|
|
||||||
type: string
|
|
||||||
required:
|
required:
|
||||||
- blocked
|
- blocked
|
||||||
- apikey
|
- apikey
|
||||||
@@ -1338,8 +1334,6 @@ definitions:
|
|||||||
type: boolean
|
type: boolean
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
password:
|
|
||||||
type: string
|
|
||||||
roles:
|
roles:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
|||||||
@@ -6523,14 +6523,8 @@
|
|||||||
},
|
},
|
||||||
"type" : "array"
|
"type" : "array"
|
||||||
},
|
},
|
||||||
"salt" : {
|
|
||||||
"type" : "string"
|
|
||||||
},
|
|
||||||
"sha256" : {
|
"sha256" : {
|
||||||
"type" : "string"
|
"type" : "string"
|
||||||
},
|
|
||||||
"sha512" : {
|
|
||||||
"type" : "string"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required" : [ "apikey", "blocked", "roles" ],
|
"required" : [ "apikey", "blocked", "roles" ],
|
||||||
@@ -6589,9 +6583,6 @@
|
|||||||
"id" : {
|
"id" : {
|
||||||
"type" : "string"
|
"type" : "string"
|
||||||
},
|
},
|
||||||
"password" : {
|
|
||||||
"type" : "string"
|
|
||||||
},
|
|
||||||
"roles" : {
|
"roles" : {
|
||||||
"items" : {
|
"items" : {
|
||||||
"type" : "string"
|
"type" : "string"
|
||||||
|
|||||||
@@ -1166,12 +1166,8 @@ definitions:
|
|||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
salt:
|
|
||||||
type: string
|
|
||||||
sha256:
|
sha256:
|
||||||
type: string
|
type: string
|
||||||
sha512:
|
|
||||||
type: string
|
|
||||||
required:
|
required:
|
||||||
- blocked
|
- blocked
|
||||||
- apikey
|
- apikey
|
||||||
@@ -1219,8 +1215,6 @@ definitions:
|
|||||||
type: boolean
|
type: boolean
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
password:
|
|
||||||
type: string
|
|
||||||
roles:
|
roles:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
|||||||
@@ -116,10 +116,10 @@ func init() {
|
|||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"default_groups":{"items":{"type":"string"},"type":"array"},"default_playbooks":{"items":{"type":"string"},"type":"array"},"default_template":{"type":"string"},"icon":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","icon","default_template","default_playbooks"],"$id":"#/definitions/TicketTypeResponse"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"default_groups":{"items":{"type":"string"},"type":"array"},"default_playbooks":{"items":{"type":"string"},"type":"array"},"default_template":{"type":"string"},"icon":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","icon","default_template","default_playbooks"],"$id":"#/definitions/TicketTypeResponse"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"artifacts":{"items":{"$ref":"#/definitions/Artifact"},"type":"array"},"comments":{"items":{"$ref":"#/definitions/Comment"},"type":"array"},"created":{"format":"date-time","type":"string"},"details":{"type":"object"},"files":{"items":{"$ref":"#/definitions/File"},"type":"array"},"id":{"format":"int64","type":"integer"},"logs":{"items":{"$ref":"#/definitions/LogEntry"},"type":"array"},"modified":{"format":"date-time","type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"playbooks":{"type":"object","additionalProperties":{"$ref":"#/definitions/PlaybookResponse"}},"read":{"items":{"type":"string"},"type":"array"},"references":{"items":{"$ref":"#/definitions/Reference"},"type":"array"},"schema":{"type":"string"},"status":{"type":"string"},"tickets":{"items":{"$ref":"#/definitions/TicketSimpleResponse"},"type":"array"},"type":{"type":"string"},"write":{"items":{"type":"string"},"type":"array"}},"required":["id","name","type","status","created","modified","schema"],"$id":"#/definitions/TicketWithTickets"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"artifacts":{"items":{"$ref":"#/definitions/Artifact"},"type":"array"},"comments":{"items":{"$ref":"#/definitions/Comment"},"type":"array"},"created":{"format":"date-time","type":"string"},"details":{"type":"object"},"files":{"items":{"$ref":"#/definitions/File"},"type":"array"},"id":{"format":"int64","type":"integer"},"logs":{"items":{"$ref":"#/definitions/LogEntry"},"type":"array"},"modified":{"format":"date-time","type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"playbooks":{"type":"object","additionalProperties":{"$ref":"#/definitions/PlaybookResponse"}},"read":{"items":{"type":"string"},"type":"array"},"references":{"items":{"$ref":"#/definitions/Reference"},"type":"array"},"schema":{"type":"string"},"status":{"type":"string"},"tickets":{"items":{"$ref":"#/definitions/TicketSimpleResponse"},"type":"array"},"type":{"type":"string"},"write":{"items":{"type":"string"},"type":"array"}},"required":["id","name","type","status","created","modified","schema"],"$id":"#/definitions/TicketWithTickets"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"color":{"title":"Color","type":"string","enum":["error","info","success","warning"]},"icon":{"title":"Icon (https://materialdesignicons.com)","type":"string"},"id":{"title":"ID","type":"string"},"name":{"title":"Name","type":"string"}},"required":["id","name","icon"],"$id":"#/definitions/Type"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"color":{"title":"Color","type":"string","enum":["error","info","success","warning"]},"icon":{"title":"Icon (https://materialdesignicons.com)","type":"string"},"id":{"title":"ID","type":"string"},"name":{"title":"Name","type":"string"}},"required":["id","name","icon"],"$id":"#/definitions/Type"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"apikey":{"type":"boolean"},"blocked":{"type":"boolean"},"roles":{"items":{"type":"string"},"type":"array"},"salt":{"type":"string"},"sha256":{"type":"string"},"sha512":{"type":"string"}},"required":["blocked","apikey","roles"],"$id":"#/definitions/User"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"apikey":{"type":"boolean"},"blocked":{"type":"boolean"},"roles":{"items":{"type":"string"},"type":"array"},"sha256":{"type":"string"}},"required":["blocked","apikey","roles"],"$id":"#/definitions/User"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"email":{"type":"string"},"image":{"type":"string"},"name":{"type":"string"},"timeformat":{"title":"Time Format (https://moment.github.io/luxon/docs/manual/formatting.html#table-of-tokens)","type":"string"}},"$id":"#/definitions/UserData"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"email":{"type":"string"},"image":{"type":"string"},"name":{"type":"string"},"timeformat":{"title":"Time Format (https://moment.github.io/luxon/docs/manual/formatting.html#table-of-tokens)","type":"string"}},"$id":"#/definitions/UserData"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"email":{"type":"string"},"id":{"type":"string"},"image":{"type":"string"},"name":{"type":"string"},"timeformat":{"title":"Time Format (https://moment.github.io/luxon/docs/manual/formatting.html#table-of-tokens)","type":"string"}},"required":["id"],"$id":"#/definitions/UserDataResponse"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"email":{"type":"string"},"id":{"type":"string"},"image":{"type":"string"},"name":{"type":"string"},"timeformat":{"title":"Time Format (https://moment.github.io/luxon/docs/manual/formatting.html#table-of-tokens)","type":"string"}},"required":["id"],"$id":"#/definitions/UserDataResponse"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"apikey":{"type":"boolean"},"blocked":{"type":"boolean"},"id":{"type":"string"},"password":{"type":"string"},"roles":{"items":{"type":"string"},"type":"array"}},"required":["id","blocked","roles","apikey"],"$id":"#/definitions/UserForm"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"apikey":{"type":"boolean"},"blocked":{"type":"boolean"},"id":{"type":"string"},"roles":{"items":{"type":"string"},"type":"array"}},"required":["id","blocked","roles","apikey"],"$id":"#/definitions/UserForm"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"apikey":{"type":"boolean"},"blocked":{"type":"boolean"},"id":{"type":"string"},"roles":{"items":{"type":"string"},"type":"array"}},"required":["id","blocked","roles","apikey"],"$id":"#/definitions/UserResponse"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"apikey":{"type":"boolean"},"blocked":{"type":"boolean"},"id":{"type":"string"},"roles":{"items":{"type":"string"},"type":"array"}},"required":["id","blocked","roles","apikey"],"$id":"#/definitions/UserResponse"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"aggregation":{"type":"string"},"filter":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["bar","line","pie"]},"width":{"maximum":12,"type":"integer"}},"required":["name","type","aggregation","width"],"$id":"#/definitions/Widget"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"aggregation":{"type":"string"},"filter":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["bar","line","pie"]},"width":{"maximum":12,"type":"integer"}},"required":["name","type","aggregation","width"],"$id":"#/definitions/Widget"}`),
|
||||||
)
|
)
|
||||||
@@ -588,9 +588,7 @@ type User struct {
|
|||||||
Apikey bool `json:"apikey"`
|
Apikey bool `json:"apikey"`
|
||||||
Blocked bool `json:"blocked"`
|
Blocked bool `json:"blocked"`
|
||||||
Roles []string `json:"roles"`
|
Roles []string `json:"roles"`
|
||||||
Salt *string `json:"salt,omitempty"`
|
|
||||||
Sha256 *string `json:"sha256,omitempty"`
|
Sha256 *string `json:"sha256,omitempty"`
|
||||||
Sha512 *string `json:"sha512,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserData struct {
|
type UserData struct {
|
||||||
@@ -609,11 +607,10 @@ type UserDataResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UserForm struct {
|
type UserForm struct {
|
||||||
Apikey bool `json:"apikey"`
|
Apikey bool `json:"apikey"`
|
||||||
Blocked bool `json:"blocked"`
|
Blocked bool `json:"blocked"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Password *string `json:"password,omitempty"`
|
Roles []string `json:"roles"`
|
||||||
Roles []string `json:"roles"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserResponse struct {
|
type UserResponse struct {
|
||||||
|
|||||||
@@ -2186,24 +2186,12 @@ export interface User {
|
|||||||
* @memberof User
|
* @memberof User
|
||||||
*/
|
*/
|
||||||
'roles': Array<string>;
|
'roles': Array<string>;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof User
|
|
||||||
*/
|
|
||||||
'salt'?: string;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof User
|
* @memberof User
|
||||||
*/
|
*/
|
||||||
'sha256'?: string;
|
'sha256'?: string;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof User
|
|
||||||
*/
|
|
||||||
'sha512'?: string;
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -2297,12 +2285,6 @@ export interface UserForm {
|
|||||||
* @memberof UserForm
|
* @memberof UserForm
|
||||||
*/
|
*/
|
||||||
'id': string;
|
'id': string;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof UserForm
|
|
||||||
*/
|
|
||||||
'password'?: string;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {Array<string>}
|
* @type {Array<string>}
|
||||||
|
|||||||
@@ -130,6 +130,11 @@ export default Vue.extend({
|
|||||||
components: {
|
components: {
|
||||||
VueCropper
|
VueCropper
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
"userdata": function () {
|
||||||
|
this.editoruserdata = this.userdata;
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
saveUserData: function() {
|
saveUserData: function() {
|
||||||
this.$emit("save", this.editoruserdata);
|
this.$emit("save", this.editoruserdata);
|
||||||
|
|||||||
@@ -17,11 +17,12 @@
|
|||||||
<span v-if="user.apikey">API Key</span>
|
<span v-if="user.apikey">API Key</span>
|
||||||
<span v-else>User</span>
|
<span v-else>User</span>
|
||||||
</h2>
|
</h2>
|
||||||
|
<i>Users can only be created via OIDC.</i>
|
||||||
<v-form>
|
<v-form>
|
||||||
<v-btn-toggle v-model="user.apikey" mandatory dense>
|
<!--v-btn-toggle v-model="user.apikey" mandatory dense>
|
||||||
<v-btn :value="false">User</v-btn>
|
<v-btn :value="false">User</v-btn>
|
||||||
<v-btn :value="true">API Key</v-btn>
|
<v-btn :value="true">API Key</v-btn>
|
||||||
</v-btn-toggle>
|
</v-btn-toggle-->
|
||||||
<v-text-field label="ID" v-model="user.id" class="mb-2" :rules="[
|
<v-text-field label="ID" v-model="user.id" class="mb-2" :rules="[
|
||||||
v => !!v || 'ID is required',
|
v => !!v || 'ID is required',
|
||||||
v => (v && v.length < 254) || 'ID must be between 1 and 254 characters',
|
v => (v && v.length < 254) || 'ID must be between 1 and 254 characters',
|
||||||
@@ -58,7 +59,7 @@
|
|||||||
<span v-if="user.apikey">(API Key)</span>
|
<span v-if="user.apikey">(API Key)</span>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<v-text-field v-if="!user.apikey" label="New Password (leave empty to keep)" v-model="user.password" hide-details class="mb-4"></v-text-field>
|
<!--v-text-field v-if="!user.apikey" label="New Password (leave empty to keep)" v-model="user.password" hide-details class="mb-4"></v-text-field-->
|
||||||
<v-checkbox v-if="!user.apikey" label="Blocked" v-model="user.blocked" hide-details class="mb-4"></v-checkbox>
|
<v-checkbox v-if="!user.apikey" label="Blocked" v-model="user.blocked" hide-details class="mb-4"></v-checkbox>
|
||||||
|
|
||||||
<v-select multiple chips v-if="!user.apikey" label="Roles" v-model="user.roles" :items="['analyst', 'engineer', 'admin']"></v-select>
|
<v-select multiple chips v-if="!user.apikey" label="Roles" v-model="user.roles" :items="['analyst', 'engineer', 'admin']"></v-select>
|
||||||
|
|||||||
Reference in New Issue
Block a user