Add KeyToken authorization

This commit is contained in:
2023-04-21 21:45:16 +02:00
parent 16f6ab4861
commit b1bd278f9b
49 changed files with 3109 additions and 1313 deletions

View File

@@ -14,6 +14,7 @@ import (
)
type AppContext struct {
app *Application
inner context.Context
cancelFunc context.CancelFunc
cancelled bool
@@ -22,8 +23,9 @@ type AppContext struct {
ginContext *gin.Context
}
func CreateAppContext(g *gin.Context, innerCtx context.Context, cancelFn context.CancelFunc) *AppContext {
func CreateAppContext(app *Application, g *gin.Context, innerCtx context.Context, cancelFn context.CancelFunc) *AppContext {
return &AppContext{
app: app,
inner: innerCtx,
cancelFunc: cancelFn,
cancelled: false,

View File

@@ -248,7 +248,7 @@ func (app *Application) StartRequest(g *gin.Context, uri any, query any, body an
}
ictx, cancel := context.WithTimeout(context.Background(), app.Config.RequestTimeout)
actx := CreateAppContext(g, ictx, cancel)
actx := CreateAppContext(app, g, ictx, cancel)
authheader := g.GetHeader("Authorization")
@@ -280,19 +280,19 @@ func (app *Application) getPermissions(ctx *AppContext, hdr string) (models.Perm
key := strings.TrimSpace(hdr[4:])
user, err := app.Database.Primary.GetUserByKey(ctx, key)
tok, err := app.Database.Primary.GetKeyTokenByToken(ctx, key)
if err != nil {
return models.PermissionSet{}, err
}
if user != nil && user.SendKey == key {
return models.PermissionSet{UserID: langext.Ptr(user.UserID), KeyType: models.PermKeyTypeUserSend}, nil
}
if user != nil && user.ReadKey == key {
return models.PermissionSet{UserID: langext.Ptr(user.UserID), KeyType: models.PermKeyTypeUserRead}, nil
}
if user != nil && user.AdminKey == key {
return models.PermissionSet{UserID: langext.Ptr(user.UserID), KeyType: models.PermKeyTypeUserAdmin}, nil
if tok != nil {
err = app.Database.Primary.UpdateKeyTokenLastUsed(ctx, tok.KeyTokenID)
if err != nil {
return models.PermissionSet{}, err
}
return models.PermissionSet{Token: tok}, nil
}
return models.NewEmptyPermissions(), nil
@@ -309,9 +309,8 @@ func (app *Application) GetOrCreateChannel(ctx *AppContext, userid models.UserID
}
subscribeKey := app.GenerateRandomAuthKey()
sendKey := app.GenerateRandomAuthKey()
newChan, err := app.Database.Primary.CreateChannel(ctx, userid, displayChanName, intChanName, subscribeKey, sendKey)
newChan, err := app.Database.Primary.CreateChannel(ctx, userid, displayChanName, intChanName, subscribeKey)
if err != nil {
return models.Channel{}, err
}

View File

@@ -4,94 +4,116 @@ import (
"blackforestbytes.com/simplecloudnotifier/api/apierr"
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
"blackforestbytes.com/simplecloudnotifier/models"
"database/sql"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
)
func (ac *AppContext) CheckPermissionUserRead(userid models.UserID) *ginresp.HTTPResponse {
p := ac.permissions
if p.UserID != nil && *p.UserID == userid && p.KeyType == models.PermKeyTypeUserRead {
return nil
}
if p.UserID != nil && *p.UserID == userid && p.KeyType == models.PermKeyTypeUserAdmin {
if p.Token != nil && p.Token.IsUserRead(userid) {
return nil
}
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
func (ac *AppContext) CheckPermissionRead() *ginresp.HTTPResponse {
func (ac *AppContext) CheckPermissionSelfAllMessagesRead() *ginresp.HTTPResponse {
p := ac.permissions
if p.UserID != nil && p.KeyType == models.PermKeyTypeUserRead {
if p.Token != nil && p.Token.IsAllMessagesRead(p.Token.OwnerUserID) {
return nil
}
if p.UserID != nil && p.KeyType == models.PermKeyTypeUserAdmin {
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
func (ac *AppContext) CheckPermissionAllMessagesRead(userid models.UserID) *ginresp.HTTPResponse {
p := ac.permissions
if p.Token != nil && p.Token.IsAllMessagesRead(userid) {
return nil
}
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
func (ac *AppContext) CheckPermissionChanMessagesRead(channel models.Channel) *ginresp.HTTPResponse {
p := ac.permissions
if p.Token != nil && p.Token.IsChannelMessagesRead(channel.ChannelID) {
if channel.OwnerUserID == p.Token.OwnerUserID {
return nil // owned channel
} else {
sub, err := ac.app.Database.Primary.GetSubscriptionBySubscriber(ac, p.Token.OwnerUserID, channel.ChannelID)
if err == sql.ErrNoRows {
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
if err != nil {
return langext.Ptr(ginresp.APIError(ac.ginContext, 500, apierr.DATABASE_ERROR, "Failed to query subscription", err))
}
if !sub.Confirmed {
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
}
}
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
func (ac *AppContext) CheckPermissionUserAdmin(userid models.UserID) *ginresp.HTTPResponse {
p := ac.permissions
if p.UserID != nil && *p.UserID == userid && p.KeyType == models.PermKeyTypeUserAdmin {
if p.Token != nil && p.Token.IsAdmin(userid) {
return nil
}
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
func (ac *AppContext) CheckPermissionSend() *ginresp.HTTPResponse {
p := ac.permissions
if p.UserID != nil && p.KeyType == models.PermKeyTypeUserSend {
return nil
func (ac *AppContext) CheckPermissionSend(channel models.Channel, key string) (*models.KeyToken, *ginresp.HTTPResponse) {
keytok, err := ac.app.Database.Primary.GetKeyTokenByToken(ac, key)
if err != nil {
return nil, langext.Ptr(ginresp.APIError(ac.ginContext, 500, apierr.DATABASE_ERROR, "Failed to query token", err))
}
if p.UserID != nil && p.KeyType == models.PermKeyTypeUserAdmin {
return nil
if keytok == nil {
return nil, langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
if keytok.IsChannelMessagesSend(channel) {
return keytok, nil
}
return nil, langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
func (ac *AppContext) CheckPermissionAny() *ginresp.HTTPResponse {
func (ac *AppContext) CheckPermissionMessageRead(msg models.Message) bool {
p := ac.permissions
if p.KeyType == models.PermKeyTypeNone {
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
return nil
}
func (ac *AppContext) CheckPermissionMessageReadDirect(msg models.Message) bool {
p := ac.permissions
if p.UserID != nil && msg.OwnerUserID == *p.UserID && p.KeyType == models.PermKeyTypeUserRead {
return true
}
if p.UserID != nil && msg.OwnerUserID == *p.UserID && p.KeyType == models.PermKeyTypeUserAdmin {
if p.Token != nil && p.Token.IsChannelMessagesRead(msg.ChannelID) {
return true
}
return false
}
func (ac *AppContext) CheckPermissionAny() *ginresp.HTTPResponse {
p := ac.permissions
if p.Token == nil {
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
return nil
}
func (ac *AppContext) GetPermissionUserID() *models.UserID {
if ac.permissions.UserID == nil {
if ac.permissions.Token == nil {
return nil
} else {
return langext.Ptr(*ac.permissions.UserID)
return langext.Ptr(ac.permissions.Token.OwnerUserID)
}
}
func (ac *AppContext) IsPermissionUserRead() bool {
p := ac.permissions
return p.KeyType == models.PermKeyTypeUserRead || p.KeyType == models.PermKeyTypeUserAdmin
}
func (ac *AppContext) IsPermissionUserSend() bool {
p := ac.permissions
return p.KeyType == models.PermKeyTypeUserSend || p.KeyType == models.PermKeyTypeUserAdmin
}
func (ac *AppContext) IsPermissionUserAdmin() bool {
p := ac.permissions
return p.KeyType == models.PermKeyTypeUserAdmin
func (ac *AppContext) GetPermissionKeyTokenID() *models.KeyTokenID {
if ac.permissions.Token == nil {
return nil
} else {
return langext.Ptr(ac.permissions.Token.KeyTokenID)
}
}