@@ -9,7 +9,7 @@ import (
|
|||||||
"git.aiterp.net/rpdata/api/graphql/loader"
|
"git.aiterp.net/rpdata/api/graphql/loader"
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver"
|
"git.aiterp.net/rpdata/api/graphql/resolver"
|
||||||
"git.aiterp.net/rpdata/api/graphql/schema"
|
"git.aiterp.net/rpdata/api/graphql/schema"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/internal/store"
|
"git.aiterp.net/rpdata/api/internal/store"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/file"
|
"git.aiterp.net/rpdata/api/model/file"
|
||||||
@@ -46,19 +46,19 @@ func main() {
|
|||||||
|
|
||||||
relayHandler := &relay.Handler{Schema: schema}
|
relayHandler := &relay.Handler{Schema: schema}
|
||||||
http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
|
||||||
r = session.Load(w, r)
|
|
||||||
|
|
||||||
l := loader.New()
|
l := loader.New()
|
||||||
r = r.WithContext(l.ToContext(r.Context()))
|
r = r.WithContext(l.ToContext(r.Context()))
|
||||||
|
|
||||||
|
r = auth.RequestWithToken(r)
|
||||||
|
|
||||||
relayHandler.ServeHTTP(w, r)
|
relayHandler.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
|
|
||||||
http.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
|
||||||
r = session.Load(w, r)
|
r = auth.RequestWithToken(r)
|
||||||
sess := session.FromContext(r.Context())
|
|
||||||
user := sess.User()
|
token := auth.TokenFromContext(r.Context())
|
||||||
if user == nil || !user.Permitted("file.upload") {
|
if !token.Permitted("file.upload") {
|
||||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := file.Upload(r.Context(), header.Filename, header.Header.Get("Content-Type"), user.ID, header.Size, formFile)
|
file, err := file.Upload(r.Context(), header.Filename, header.Header.Get("Content-Type"), token.UserID, header.Size, formFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Internal (2): "+err.Error(), http.StatusInternalServerError)
|
http.Error(w, "Internal (2): "+err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/channel"
|
"git.aiterp.net/rpdata/api/model/channel"
|
||||||
)
|
)
|
||||||
@@ -24,8 +24,8 @@ type ChannelAddArgs struct {
|
|||||||
func (r *MutationResolver) AddChannel(ctx context.Context, args *ChannelAddArgs) (*types.ChannelResolver, error) {
|
func (r *MutationResolver) AddChannel(ctx context.Context, args *ChannelAddArgs) (*types.ChannelResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("channel.add") {
|
if !token.Permitted("channel.add") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ func (r *MutationResolver) AddChannel(ctx context.Context, args *ChannelAddArgs)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Channel", "add", user.ID, channel.Name, map[string]interface{}{
|
go change.Submit("Channel", "add", token.UserID, channel.Name, map[string]interface{}{
|
||||||
"logged": channel.Logged,
|
"logged": channel.Logged,
|
||||||
"hub": channel.Hub,
|
"hub": channel.Hub,
|
||||||
"location": input.LocationName,
|
"location": input.LocationName,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/story"
|
"git.aiterp.net/rpdata/api/model/story"
|
||||||
)
|
)
|
||||||
@@ -25,8 +25,8 @@ type AddChapterArgs struct {
|
|||||||
func (r *MutationResolver) AddChapter(ctx context.Context, args *AddChapterArgs) (*types.ChapterResolver, error) {
|
func (r *MutationResolver) AddChapter(ctx context.Context, args *AddChapterArgs) (*types.ChapterResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member", "chapter.add") {
|
if !token.Permitted("member", "chapter.add") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,11 +35,11 @@ func (r *MutationResolver) AddChapter(ctx context.Context, args *AddChapterArgs)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
author := user.ID
|
author := token.UserID
|
||||||
if input.Author != nil {
|
if input.Author != nil {
|
||||||
author = *input.Author
|
author = *input.Author
|
||||||
|
|
||||||
if user.ID != author && !user.Permitted("chapter.add") {
|
if token.UserID != author && !token.Permitted("chapter.add") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ func (r *MutationResolver) AddChapter(ctx context.Context, args *AddChapterArgs)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Chapter", "add", user.ID, chapter.ID, map[string]interface{}{
|
go change.Submit("Chapter", "add", token.UserID, chapter.ID, map[string]interface{}{
|
||||||
"title": input.Title,
|
"title": input.Title,
|
||||||
"author": author,
|
"author": author,
|
||||||
"fictionalDate": fictionalDate,
|
"fictionalDate": fictionalDate,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/character"
|
"git.aiterp.net/rpdata/api/model/character"
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
@@ -23,8 +23,8 @@ type AddCharacterInput struct {
|
|||||||
// AddCharacter resolves the addCharacter mutation
|
// AddCharacter resolves the addCharacter mutation
|
||||||
func (r *MutationResolver) AddCharacter(ctx context.Context, args struct{ Input *AddCharacterInput }) (*types.CharacterResolver, error) {
|
func (r *MutationResolver) AddCharacter(ctx context.Context, args struct{ Input *AddCharacterInput }) (*types.CharacterResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member", "character.add") {
|
if !token.Permitted("member", "character.add") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,11 +39,11 @@ func (r *MutationResolver) AddCharacter(ctx context.Context, args struct{ Input
|
|||||||
shortName = strings.SplitN(input.Name, " ", 2)[0]
|
shortName = strings.SplitN(input.Name, " ", 2)[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
author := user.ID
|
author := token.UserID
|
||||||
if input.Author != nil {
|
if input.Author != nil {
|
||||||
author = *input.Author
|
author = *input.Author
|
||||||
|
|
||||||
if author != user.ID && !user.Permitted("character.add") {
|
if author != token.UserID && !token.Permitted("character.add") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ func (r *MutationResolver) AddCharacter(ctx context.Context, args struct{ Input
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Character", "add", user.ID, character.ID, map[string]interface{}{
|
go change.Submit("Character", "add", token.UserID, character.ID, map[string]interface{}{
|
||||||
"name": character.Name,
|
"name": character.Name,
|
||||||
"nick": character.Nicks[0],
|
"nick": character.Nicks[0],
|
||||||
"author": character.Author,
|
"author": character.Author,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/character"
|
"git.aiterp.net/rpdata/api/model/character"
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
@@ -20,8 +20,8 @@ type AddCharacterNickInput struct {
|
|||||||
func (r *MutationResolver) AddCharacterNick(ctx context.Context, args struct{ Input *AddCharacterNickInput }) (*types.CharacterResolver, error) {
|
func (r *MutationResolver) AddCharacterNick(ctx context.Context, args struct{ Input *AddCharacterNickInput }) (*types.CharacterResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member") {
|
if !token.Permitted("member") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ func (r *MutationResolver) AddCharacterNick(ctx context.Context, args struct{ In
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if character.Author != user.ID && !user.Permitted("character.edit") {
|
if character.Author != token.UserID && !token.Permitted("character.edit") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ func (r *MutationResolver) AddCharacterNick(ctx context.Context, args struct{ In
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Character", "add.nick", user.ID, character.ID, map[string]interface{}{
|
go change.Submit("Character", "add.nick", token.UserID, character.ID, map[string]interface{}{
|
||||||
"nick": input.Nick,
|
"nick": input.Nick,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
)
|
)
|
||||||
@@ -26,8 +26,8 @@ type LogAddArgs struct {
|
|||||||
func (r *MutationResolver) AddLog(ctx context.Context, args *LogAddArgs) (*types.LogResolver, error) {
|
func (r *MutationResolver) AddLog(ctx context.Context, args *LogAddArgs) (*types.LogResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("log.add") {
|
if !token.Permitted("log.add") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ func (r *MutationResolver) AddLog(ctx context.Context, args *LogAddArgs) (*types
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Log", "add", user.ID, log.ID, map[string]interface{}{
|
go change.Submit("Log", "add", token.UserID, log.ID, map[string]interface{}{
|
||||||
"channel": log.Channel,
|
"channel": log.Channel,
|
||||||
"title": log.Title,
|
"title": log.Title,
|
||||||
"event": log.Event,
|
"event": log.Event,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
)
|
)
|
||||||
@@ -25,8 +25,8 @@ type PostAddArgs struct {
|
|||||||
func (r *MutationResolver) AddPost(ctx context.Context, args *PostAddArgs) (*types.PostResolver, error) {
|
func (r *MutationResolver) AddPost(ctx context.Context, args *PostAddArgs) (*types.PostResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("post.add") {
|
if !token.Permitted("post.add") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ func (r *MutationResolver) AddPost(ctx context.Context, args *PostAddArgs) (*typ
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Post", "add", user.ID, post.ID, map[string]interface{}{
|
go change.Submit("Post", "add", token.UserID, post.ID, map[string]interface{}{
|
||||||
"logId": post.LogID,
|
"logId": post.LogID,
|
||||||
"time": post.Time,
|
"time": post.Time,
|
||||||
"kind": post.Kind,
|
"kind": post.Kind,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/story"
|
"git.aiterp.net/rpdata/api/model/story"
|
||||||
)
|
)
|
||||||
@@ -30,16 +30,16 @@ type StoryAddArgs struct {
|
|||||||
func (r *MutationResolver) AddStory(ctx context.Context, args *StoryAddArgs) (*types.StoryResolver, error) {
|
func (r *MutationResolver) AddStory(ctx context.Context, args *StoryAddArgs) (*types.StoryResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member", "story.add") {
|
if !token.Permitted("member", "story.add") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
author := user.ID
|
author := token.UserID
|
||||||
if input.Author != nil {
|
if input.Author != nil {
|
||||||
author = *input.Author
|
author = *input.Author
|
||||||
|
|
||||||
if user.ID != author && !user.Permitted("story.add") {
|
if token.UserID != author && !token.Permitted("story.add") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ func (r *MutationResolver) AddStory(ctx context.Context, args *StoryAddArgs) (*t
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Story", "add", user.ID, story.ID, map[string]interface{}{
|
go change.Submit("Story", "add", token.UserID, story.ID, map[string]interface{}{
|
||||||
"name": input.Name,
|
"name": input.Name,
|
||||||
"category": input.Category,
|
"category": input.Category,
|
||||||
"author": input.Author,
|
"author": input.Author,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/story"
|
"git.aiterp.net/rpdata/api/model/story"
|
||||||
)
|
)
|
||||||
@@ -25,8 +25,8 @@ func (r *MutationResolver) AddStoryTag(ctx context.Context, args *StoryTagAddArg
|
|||||||
input := args.Input
|
input := args.Input
|
||||||
tag := story.Tag{Kind: input.Tag.Kind, Name: input.Tag.Name}
|
tag := story.Tag{Kind: input.Tag.Kind, Name: input.Tag.Name}
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member", "story.edit") {
|
if !token.Permitted("member", "story.edit") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ func (r *MutationResolver) AddStoryTag(ctx context.Context, args *StoryTagAddArg
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if story.Author != user.ID && !user.Permitted("story.edit") {
|
if story.Author != token.UserID && !token.Permitted("story.edit") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ func (r *MutationResolver) AddStoryTag(ctx context.Context, args *StoryTagAddArg
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Story", "add.tag", user.ID, story.ID, map[string]interface{}{
|
go change.Submit("Story", "add.tag", token.UserID, story.ID, map[string]interface{}{
|
||||||
"kind": tag.Kind,
|
"kind": tag.Kind,
|
||||||
"name": tag.Name,
|
"name": tag.Name,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/channel"
|
"git.aiterp.net/rpdata/api/model/channel"
|
||||||
)
|
)
|
||||||
@@ -24,8 +24,8 @@ type ChannelEditArgs struct {
|
|||||||
func (r *MutationResolver) EditChannel(ctx context.Context, args *ChannelEditArgs) (*types.ChannelResolver, error) {
|
func (r *MutationResolver) EditChannel(ctx context.Context, args *ChannelEditArgs) (*types.ChannelResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("channel.edit") {
|
if !token.Permitted("channel.edit") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ func (r *MutationResolver) EditChannel(ctx context.Context, args *ChannelEditArg
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Channel", "edit", user.ID, channel.Name, map[string]interface{}{
|
go change.Submit("Channel", "edit", token.UserID, channel.Name, map[string]interface{}{
|
||||||
"logged": input.Logged,
|
"logged": input.Logged,
|
||||||
"hub": input.Hub,
|
"hub": input.Hub,
|
||||||
"location": input.LocationName,
|
"location": input.LocationName,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/story"
|
"git.aiterp.net/rpdata/api/model/story"
|
||||||
)
|
)
|
||||||
@@ -24,8 +24,8 @@ type EditChapterArgs struct {
|
|||||||
func (r *MutationResolver) EditChapter(ctx context.Context, args *EditChapterArgs) (*types.ChapterResolver, error) {
|
func (r *MutationResolver) EditChapter(ctx context.Context, args *EditChapterArgs) (*types.ChapterResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member", "chapter.edit") {
|
if !token.Permitted("member", "chapter.edit") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ func (r *MutationResolver) EditChapter(ctx context.Context, args *EditChapterArg
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if chapter.Author != user.ID && !user.Permitted("chapter.edit") {
|
if chapter.Author != token.UserID && !token.Permitted("chapter.edit") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ func (r *MutationResolver) EditChapter(ctx context.Context, args *EditChapterArg
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Chapter", "edit", user.ID, chapter.ID, map[string]interface{}{
|
go change.Submit("Chapter", "edit", token.UserID, chapter.ID, map[string]interface{}{
|
||||||
"title": input.Title,
|
"title": input.Title,
|
||||||
"source": input.Source,
|
"source": input.Source,
|
||||||
"fictionalDate": fictionalDate,
|
"fictionalDate": fictionalDate,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/character"
|
"git.aiterp.net/rpdata/api/model/character"
|
||||||
)
|
)
|
||||||
@@ -21,8 +21,8 @@ type CharacterEditInput struct {
|
|||||||
func (r *MutationResolver) EditCharacter(ctx context.Context, args struct{ Input *CharacterEditInput }) (*types.CharacterResolver, error) {
|
func (r *MutationResolver) EditCharacter(ctx context.Context, args struct{ Input *CharacterEditInput }) (*types.CharacterResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member") {
|
if !token.Permitted("member") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ func (r *MutationResolver) EditCharacter(ctx context.Context, args struct{ Input
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if character.Author != user.ID && !user.Permitted("character.edit") {
|
if character.Author != token.UserID && !token.Permitted("character.edit") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ func (r *MutationResolver) EditCharacter(ctx context.Context, args struct{ Input
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Character", "edit", user.ID, character.ID, map[string]interface{}{
|
go change.Submit("Character", "edit", token.UserID, character.ID, map[string]interface{}{
|
||||||
"name": character.Name,
|
"name": character.Name,
|
||||||
"shortName": character.ShortName,
|
"shortName": character.ShortName,
|
||||||
"description": character.Description,
|
"description": character.Description,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/file"
|
"git.aiterp.net/rpdata/api/model/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,8 +21,8 @@ type FileEditArgs struct {
|
|||||||
func (r *MutationResolver) EditFile(ctx context.Context, args *FileEditArgs) (*types.FileResolver, error) {
|
func (r *MutationResolver) EditFile(ctx context.Context, args *FileEditArgs) (*types.FileResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member") {
|
if !token.Permitted("member") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ func (r *MutationResolver) EditFile(ctx context.Context, args *FileEditArgs) (*t
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if file.Author != user.ID && !user.Permitted("file.edit") {
|
if file.Author != token.UserID && !token.Permitted("file.edit") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
)
|
)
|
||||||
@@ -24,8 +24,8 @@ type LogEditArgs struct {
|
|||||||
func (r *MutationResolver) EditLog(ctx context.Context, args *LogEditArgs) (*types.LogResolver, error) {
|
func (r *MutationResolver) EditLog(ctx context.Context, args *LogEditArgs) (*types.LogResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("log.edit") {
|
if !token.Permitted("log.edit") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ func (r *MutationResolver) EditLog(ctx context.Context, args *LogEditArgs) (*typ
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Log", "edit", user.ID, log.ID, map[string]interface{}{
|
go change.Submit("Log", "edit", token.UserID, log.ID, map[string]interface{}{
|
||||||
"channel": log.Channel,
|
"channel": log.Channel,
|
||||||
"title": input.Title,
|
"title": input.Title,
|
||||||
"event": input.Event,
|
"event": input.Event,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
)
|
)
|
||||||
@@ -25,8 +25,8 @@ type PostEditArgs struct {
|
|||||||
func (r *MutationResolver) EditPost(ctx context.Context, args *PostEditArgs) (*types.PostResolver, error) {
|
func (r *MutationResolver) EditPost(ctx context.Context, args *PostEditArgs) (*types.PostResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("post.edit") {
|
if !token.Permitted("post.edit") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ func (r *MutationResolver) EditPost(ctx context.Context, args *PostEditArgs) (*t
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Post", "edit", user.ID, post.ID, map[string]interface{}{
|
go change.Submit("Post", "edit", token.UserID, post.ID, map[string]interface{}{
|
||||||
"time": postTime,
|
"time": postTime,
|
||||||
"kind": input.Kind,
|
"kind": input.Kind,
|
||||||
"nick": input.Nick,
|
"nick": input.Nick,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/story"
|
"git.aiterp.net/rpdata/api/model/story"
|
||||||
)
|
)
|
||||||
@@ -27,8 +27,8 @@ type StoryEditArgs struct {
|
|||||||
func (r *MutationResolver) EditStory(ctx context.Context, args *StoryEditArgs) (*types.StoryResolver, error) {
|
func (r *MutationResolver) EditStory(ctx context.Context, args *StoryEditArgs) (*types.StoryResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member", "story.edit") {
|
if !token.Permitted("member", "story.edit") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ func (r *MutationResolver) EditStory(ctx context.Context, args *StoryEditArgs) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if story.Author != user.ID && !user.Permitted("story.edit") {
|
if story.Author != token.UserID && !token.Permitted("story.edit") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ func (r *MutationResolver) EditStory(ctx context.Context, args *StoryEditArgs) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Story", "edit", user.ID, story.ID, map[string]interface{}{
|
go change.Submit("Story", "edit", token.UserID, story.ID, map[string]interface{}{
|
||||||
"name": input.Name,
|
"name": input.Name,
|
||||||
"category": input.Category,
|
"category": input.Category,
|
||||||
"author": input.Author,
|
"author": input.Author,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
)
|
)
|
||||||
@@ -21,8 +21,8 @@ type PostMoveArgs struct {
|
|||||||
func (r *MutationResolver) MovePost(ctx context.Context, args *PostMoveArgs) (*types.PostResolver, error) {
|
func (r *MutationResolver) MovePost(ctx context.Context, args *PostMoveArgs) (*types.PostResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("post.move") {
|
if !token.Permitted("post.move") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ func (r *MutationResolver) MovePost(ctx context.Context, args *PostMoveArgs) (*t
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Post", "move", user.ID, post.ID, map[string]interface{}{
|
go change.Submit("Post", "move", token.UserID, post.ID, map[string]interface{}{
|
||||||
"logId": post.LogID,
|
"logId": post.LogID,
|
||||||
"targetIndex": input.ToPosition,
|
"targetIndex": input.ToPosition,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/channel"
|
"git.aiterp.net/rpdata/api/model/channel"
|
||||||
)
|
)
|
||||||
@@ -16,8 +16,8 @@ type RemoveChannelArgs struct {
|
|||||||
|
|
||||||
// RemoveChannel resolves the editChannel mutation
|
// RemoveChannel resolves the editChannel mutation
|
||||||
func (r *MutationResolver) RemoveChannel(ctx context.Context, args RemoveChannelArgs) (*types.ChannelResolver, error) {
|
func (r *MutationResolver) RemoveChannel(ctx context.Context, args RemoveChannelArgs) (*types.ChannelResolver, error) {
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("channel.remove") {
|
if !token.Permitted("channel.remove") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ func (r *MutationResolver) RemoveChannel(ctx context.Context, args RemoveChannel
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Channel", "remove", user.ID, channel.Name, nil)
|
go change.Submit("Channel", "remove", token.UserID, channel.Name, nil)
|
||||||
|
|
||||||
return &types.ChannelResolver{C: channel}, nil
|
return &types.ChannelResolver{C: channel}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/story"
|
"git.aiterp.net/rpdata/api/model/story"
|
||||||
)
|
)
|
||||||
@@ -16,8 +16,8 @@ type RemoveChapterArgs struct {
|
|||||||
|
|
||||||
// RemoveChapter resolves the removeChapter mutation
|
// RemoveChapter resolves the removeChapter mutation
|
||||||
func (r *MutationResolver) RemoveChapter(ctx context.Context, args *RemoveChapterArgs) (*types.ChapterResolver, error) {
|
func (r *MutationResolver) RemoveChapter(ctx context.Context, args *RemoveChapterArgs) (*types.ChapterResolver, error) {
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member", "chapter.edit") {
|
if !token.Permitted("member", "chapter.edit") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ func (r *MutationResolver) RemoveChapter(ctx context.Context, args *RemoveChapte
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Chapter", "remove", user.ID, chapter.ID, nil)
|
go change.Submit("Chapter", "remove", token.UserID, chapter.ID, nil)
|
||||||
|
|
||||||
return &types.ChapterResolver{C: chapter}, nil
|
return &types.ChapterResolver{C: chapter}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/character"
|
"git.aiterp.net/rpdata/api/model/character"
|
||||||
)
|
)
|
||||||
@@ -16,8 +16,8 @@ type RemoveCharacterArgs struct {
|
|||||||
|
|
||||||
// RemoveCharacter resolves the removeCharacter mutation
|
// RemoveCharacter resolves the removeCharacter mutation
|
||||||
func (r *MutationResolver) RemoveCharacter(ctx context.Context, args RemoveCharacterArgs) (*types.CharacterResolver, error) {
|
func (r *MutationResolver) RemoveCharacter(ctx context.Context, args RemoveCharacterArgs) (*types.CharacterResolver, error) {
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member") {
|
if !token.Permitted("member") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ func (r *MutationResolver) RemoveCharacter(ctx context.Context, args RemoveChara
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if character.Author != user.ID && !user.Permitted("character.remove") {
|
if character.Author != token.UserID && !token.Permitted("character.remove") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ func (r *MutationResolver) RemoveCharacter(ctx context.Context, args RemoveChara
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Character", "remove", user.ID, character.ID, map[string]interface{}{
|
go change.Submit("Character", "remove", token.UserID, character.ID, map[string]interface{}{
|
||||||
"name": character.Name,
|
"name": character.Name,
|
||||||
"author": character.Author,
|
"author": character.Author,
|
||||||
"nicks": character.Nicks,
|
"nicks": character.Nicks,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/character"
|
"git.aiterp.net/rpdata/api/model/character"
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
@@ -20,8 +20,8 @@ type RemoveCharacterNick struct {
|
|||||||
func (r *MutationResolver) RemoveCharacterNick(ctx context.Context, args struct{ Input *RemoveCharacterNick }) (*types.CharacterResolver, error) {
|
func (r *MutationResolver) RemoveCharacterNick(ctx context.Context, args struct{ Input *RemoveCharacterNick }) (*types.CharacterResolver, error) {
|
||||||
input := args.Input
|
input := args.Input
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member") {
|
if !token.Permitted("member") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ func (r *MutationResolver) RemoveCharacterNick(ctx context.Context, args struct{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if character.Author != user.ID && !user.Permitted("character.edit") {
|
if character.Author != token.UserID && !token.Permitted("character.edit") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ func (r *MutationResolver) RemoveCharacterNick(ctx context.Context, args struct{
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Character", "remove.nick", user.ID, character.ID, map[string]interface{}{
|
go change.Submit("Character", "remove.nick", token.UserID, character.ID, map[string]interface{}{
|
||||||
"nick": input.Nick,
|
"nick": input.Nick,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/file"
|
"git.aiterp.net/rpdata/api/model/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,8 +15,8 @@ type RemoveFileArgs struct {
|
|||||||
|
|
||||||
// RemoveFile resolves the removeFIle mutation
|
// RemoveFile resolves the removeFIle mutation
|
||||||
func (r *MutationResolver) RemoveFile(ctx context.Context, args *RemoveFileArgs) (*types.FileResolver, error) {
|
func (r *MutationResolver) RemoveFile(ctx context.Context, args *RemoveFileArgs) (*types.FileResolver, error) {
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member") {
|
if !token.Permitted("member") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ func (r *MutationResolver) RemoveFile(ctx context.Context, args *RemoveFileArgs)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if file.Author != user.ID && !user.Permitted("file.remove") {
|
if file.Author != token.UserID && !token.Permitted("file.remove") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
)
|
)
|
||||||
@@ -16,8 +16,8 @@ type RemoveLogArgs struct {
|
|||||||
|
|
||||||
// RemoveLog resolves the removeLog mutation
|
// RemoveLog resolves the removeLog mutation
|
||||||
func (r *MutationResolver) RemoveLog(ctx context.Context, args *RemoveLogArgs) (*types.LogResolver, error) {
|
func (r *MutationResolver) RemoveLog(ctx context.Context, args *RemoveLogArgs) (*types.LogResolver, error) {
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("log.remove") {
|
if !token.Permitted("log.remove") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ func (r *MutationResolver) RemoveLog(ctx context.Context, args *RemoveLogArgs) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Log", "remove", user.ID, log.ID, nil)
|
go change.Submit("Log", "remove", token.UserID, log.ID, nil)
|
||||||
|
|
||||||
return &types.LogResolver{L: log}, nil
|
return &types.LogResolver{L: log}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
)
|
)
|
||||||
@@ -16,8 +16,8 @@ type PostRemoveArgs struct {
|
|||||||
|
|
||||||
// RemovePost resolves the removePost mutation
|
// RemovePost resolves the removePost mutation
|
||||||
func (r *MutationResolver) RemovePost(ctx context.Context, args PostRemoveArgs) (*types.PostResolver, error) {
|
func (r *MutationResolver) RemovePost(ctx context.Context, args PostRemoveArgs) (*types.PostResolver, error) {
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("post.remove") {
|
if !token.Permitted("post.remove") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ func (r *MutationResolver) RemovePost(ctx context.Context, args PostRemoveArgs)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Post", "remove", user.ID, post.ID, map[string]interface{}{
|
go change.Submit("Post", "remove", token.UserID, post.ID, map[string]interface{}{
|
||||||
"logId": post.LogID,
|
"logId": post.LogID,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/story"
|
"git.aiterp.net/rpdata/api/model/story"
|
||||||
)
|
)
|
||||||
@@ -16,8 +16,8 @@ type StoryRemoveArgs struct {
|
|||||||
|
|
||||||
// RemoveStory resolves the removeStory mutation
|
// RemoveStory resolves the removeStory mutation
|
||||||
func (r *MutationResolver) RemoveStory(ctx context.Context, args *StoryRemoveArgs) (*types.StoryResolver, error) {
|
func (r *MutationResolver) RemoveStory(ctx context.Context, args *StoryRemoveArgs) (*types.StoryResolver, error) {
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member", "story.edit") {
|
if !token.Permitted("member", "story.edit") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ func (r *MutationResolver) RemoveStory(ctx context.Context, args *StoryRemoveArg
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if story.Author != user.ID && !user.Permitted("story.remove") {
|
if story.Author != token.UserID && !token.Permitted("story.remove") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ func (r *MutationResolver) RemoveStory(ctx context.Context, args *StoryRemoveArg
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Story", "remove", user.ID, story.ID, nil)
|
go change.Submit("Story", "remove", token.UserID, story.ID, nil)
|
||||||
|
|
||||||
return &types.StoryResolver{S: story}, nil
|
return &types.StoryResolver{S: story}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/story"
|
"git.aiterp.net/rpdata/api/model/story"
|
||||||
)
|
)
|
||||||
@@ -25,8 +25,8 @@ func (r *MutationResolver) RemoveStoryTag(ctx context.Context, args *StoryTagRem
|
|||||||
input := args.Input
|
input := args.Input
|
||||||
tag := story.Tag{Kind: input.Tag.Kind, Name: input.Tag.Name}
|
tag := story.Tag{Kind: input.Tag.Kind, Name: input.Tag.Name}
|
||||||
|
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
if user == nil || !user.Permitted("member", "story.edit") {
|
if !token.Permitted("member", "story.edit") {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ func (r *MutationResolver) RemoveStoryTag(ctx context.Context, args *StoryTagRem
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if story.Author != user.ID && !user.Permitted("story.edit") {
|
if story.Author != token.UserID && !token.Permitted("story.edit") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ func (r *MutationResolver) RemoveStoryTag(ctx context.Context, args *StoryTagRem
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go change.Submit("Story", "remove.tag", user.ID, story.ID, map[string]interface{}{
|
go change.Submit("Story", "remove.tag", token.UserID, story.ID, map[string]interface{}{
|
||||||
"kind": tag.Kind,
|
"kind": tag.Kind,
|
||||||
"name": tag.Name,
|
"name": tag.Name,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/file"
|
"git.aiterp.net/rpdata/api/model/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,11 +19,11 @@ type FilesArgs struct {
|
|||||||
// Files resolves the file query
|
// Files resolves the file query
|
||||||
func (r *QueryResolver) Files(ctx context.Context, args *FilesArgs) ([]*types.FileResolver, error) {
|
func (r *QueryResolver) Files(ctx context.Context, args *FilesArgs) ([]*types.FileResolver, error) {
|
||||||
filter := args.Filter
|
filter := args.Filter
|
||||||
user := session.FromContext(ctx).User()
|
token := auth.TokenFromContext(ctx)
|
||||||
|
|
||||||
author := ""
|
author := ""
|
||||||
if user != nil {
|
if token != nil {
|
||||||
author = user.ID
|
author = token.UserID
|
||||||
}
|
}
|
||||||
|
|
||||||
mimeTypes := []string(nil)
|
mimeTypes := []string(nil)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/model/story"
|
"git.aiterp.net/rpdata/api/model/story"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,6 +30,8 @@ type StoriesArg struct {
|
|||||||
func (r *QueryResolver) Stories(ctx context.Context, args *StoriesArg) ([]*types.StoryResolver, error) {
|
func (r *QueryResolver) Stories(ctx context.Context, args *StoriesArg) ([]*types.StoryResolver, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
token := auth.TokenFromContext(ctx)
|
||||||
|
|
||||||
filter := args.Filter
|
filter := args.Filter
|
||||||
|
|
||||||
author := ""
|
author := ""
|
||||||
@@ -79,16 +81,15 @@ func (r *QueryResolver) Stories(ctx context.Context, args *StoriesArg) ([]*types
|
|||||||
|
|
||||||
unlisted = filter.Unlisted != nil && *filter.Unlisted == true
|
unlisted = filter.Unlisted != nil && *filter.Unlisted == true
|
||||||
if unlisted {
|
if unlisted {
|
||||||
user := session.FromContext(ctx).User()
|
if token == nil {
|
||||||
if user == nil {
|
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
if author != "" && author != user.ID && !user.Permitted("story.unlisted") {
|
if author != "" && author != token.UserID && !token.Permitted("story.unlisted") {
|
||||||
return nil, ErrPermissionDenied
|
return nil, ErrPermissionDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
author = user.ID
|
author = token.UserID
|
||||||
}
|
}
|
||||||
|
|
||||||
open = filter.Open
|
open = filter.Open
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
package types
|
|
||||||
|
|
||||||
import "git.aiterp.net/rpdata/api/internal/session"
|
|
||||||
|
|
||||||
// SessionResolver resolves Session
|
|
||||||
type SessionResolver struct{ S *session.Session }
|
|
||||||
|
|
||||||
// User resolves Session.user
|
|
||||||
func (r *SessionResolver) User() *UserResolver {
|
|
||||||
user := r.S.User()
|
|
||||||
if user == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &UserResolver{U: user}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package types
|
|
||||||
|
|
||||||
import "git.aiterp.net/rpdata/api/internal/session"
|
|
||||||
|
|
||||||
// UserResolver resulves the user type
|
|
||||||
type UserResolver struct{ U *session.User }
|
|
||||||
|
|
||||||
// ID resolves User.id
|
|
||||||
func (r *UserResolver) ID() string {
|
|
||||||
return r.U.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// Permissions resolves User.permissions
|
|
||||||
func (r *UserResolver) Permissions() []string {
|
|
||||||
return r.U.Permissions
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/internal/store"
|
||||||
|
"github.com/globalsign/mgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
var keyCollection *mgo.Collection
|
||||||
|
|
||||||
|
// A Key contains a JWT secret and the limitations of it. There are two types of
|
||||||
|
// keys, single-user keys and wildcard keys. The former is used to authenticate
|
||||||
|
// a single user (e.g. the logbot) through an API while the latter is only for
|
||||||
|
// services that can be trusted to perform its own authentication (a frontend).
|
||||||
|
type Key struct {
|
||||||
|
ID string `bson:"_id"`
|
||||||
|
Name string `bson:"name"`
|
||||||
|
User string `bson:"user"`
|
||||||
|
Secret string `bson:"secret"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidForUser returns true if the key's user is the same as
|
||||||
|
// the user, or it's a wildcard key.
|
||||||
|
func (key *Key) ValidForUser(user string) bool {
|
||||||
|
return key.User == user || key.User == "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindKey finds a key by kid (key ID)
|
||||||
|
func FindKey(kid string) (Key, error) {
|
||||||
|
key := Key{}
|
||||||
|
err := keyCollection.FindId(kid).One(&key)
|
||||||
|
|
||||||
|
return key, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewKey generates a new key for the user and name. This
|
||||||
|
// does not allow generating wildcard keys, they have to be
|
||||||
|
// manually inserted into the DB.
|
||||||
|
func NewKey(name, user string) (*Key, error) {
|
||||||
|
if user == "*" {
|
||||||
|
return nil, errors.New("auth: wildcard keys not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
secret, err := makeKeySecret()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
key := &Key{
|
||||||
|
ID: makeKeyID(),
|
||||||
|
Name: name,
|
||||||
|
User: user,
|
||||||
|
Secret: secret,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := keyCollection.Insert(key); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
store.HandleInit(func(db *mgo.Database) {
|
||||||
|
keyCollection = db.C("auth.keys")
|
||||||
|
|
||||||
|
keyCollection.EnsureIndexKey("user")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeKeyID makes a random story ID that's 16 characters long
|
||||||
|
func makeKeyID() string {
|
||||||
|
result := "K"
|
||||||
|
offset := 0
|
||||||
|
data := make([]byte, 32)
|
||||||
|
|
||||||
|
rand.Read(data)
|
||||||
|
for len(result) < 16 {
|
||||||
|
result += strconv.FormatUint(binary.LittleEndian.Uint64(data[offset:]), 36)
|
||||||
|
offset += 8
|
||||||
|
|
||||||
|
if offset >= 32 {
|
||||||
|
rand.Read(data)
|
||||||
|
offset = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result[:16]
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeKeySecret() (string, error) {
|
||||||
|
data := make([]byte, 64)
|
||||||
|
alphabet := "0123456789abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSUTVWXYZ-_"
|
||||||
|
|
||||||
|
_, err := rand.Read(data)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range data {
|
||||||
|
data[i] = alphabet[data[i]%64]
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(data), nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
jwt "github.com/dgrijalva/jwt-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
var contextKey = &struct{ data string }{"Token Context Key"}
|
||||||
|
|
||||||
|
// ErrNoKid is returned if the key id is missing from the jwt token header,
|
||||||
|
var ErrNoKid = errors.New("Missing \"kid\" field in token")
|
||||||
|
|
||||||
|
// ErrKeyNotFound is returned if the key wasn't found.
|
||||||
|
var ErrKeyNotFound = errors.New("Key not found")
|
||||||
|
|
||||||
|
// ErrInvalidClaims is returned by parseClaims if the claims cannot be parsed
|
||||||
|
var ErrInvalidClaims = errors.New("Invalid claims in token")
|
||||||
|
|
||||||
|
// ErrExpired is returned by parseClaims if the expiry date is in the past
|
||||||
|
var ErrExpired = errors.New("Claims have already expired")
|
||||||
|
|
||||||
|
// ErrWrongUser is returned by CheckToken if the key cannot represent this user
|
||||||
|
var ErrWrongUser = errors.New("Key is not valid for this user")
|
||||||
|
|
||||||
|
// ErrWrongPermissions is returned by CheckToken if the key cannot claim one or more of its permissions
|
||||||
|
var ErrWrongPermissions = errors.New("Key is not valid for this user")
|
||||||
|
|
||||||
|
// ErrDeletedUser is returned by CheckToken if the key can represent this user, but the user doesn't exist.
|
||||||
|
var ErrDeletedUser = errors.New("User was not found")
|
||||||
|
|
||||||
|
// A Token contains the parsed results from an bearer token. Its methods are safe to use with a nil receiver, but
|
||||||
|
// the userID should be checked.
|
||||||
|
type Token struct {
|
||||||
|
UserID string
|
||||||
|
Permissions []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticated returns true if the token is non-nil and parsed
|
||||||
|
func (token *Token) Authenticated() bool {
|
||||||
|
return token != nil && token.UserID != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permitted returns true if the token is non-nil and has the given permission or the "admin" permission
|
||||||
|
func (token *Token) Permitted(permissions ...string) bool {
|
||||||
|
if token == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tokenPermission := range token.Permissions {
|
||||||
|
if tokenPermission == "admin" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, permission := range permissions {
|
||||||
|
if permission == tokenPermission {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// PermittedUser checks the first permission if the user matches, the second otherwise. This is a common
|
||||||
|
// pattern.
|
||||||
|
func (token *Token) PermittedUser(userID, permissionIfUser, permissionOtherwise string) bool {
|
||||||
|
if token == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.UserID == userID {
|
||||||
|
return token.Permitted(permissionIfUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
return token.Permitted(permissionOtherwise)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenFromContext gets the token from context.
|
||||||
|
func TokenFromContext(ctx context.Context) *Token {
|
||||||
|
token, ok := ctx.Value(contextKey).(*Token)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestWithToken either returns the request, or the request with a new context that
|
||||||
|
// has the token.
|
||||||
|
func RequestWithToken(r *http.Request) *http.Request {
|
||||||
|
header := r.Header.Get("Authorization")
|
||||||
|
if header == "" {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(header, "Bearer ") {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := CheckToken(header[7:])
|
||||||
|
if err != nil {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.WithContext(context.WithValue(r.Context(), contextKey, &token))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckToken reads the token string and returns a token if everything is kosher.
|
||||||
|
func CheckToken(tokenString string) (token Token, err error) {
|
||||||
|
var key Key
|
||||||
|
|
||||||
|
jwtToken, err := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
|
||||||
|
if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("Unexpected signing method: %v", jwtToken.Header["alg"])
|
||||||
|
}
|
||||||
|
|
||||||
|
kid, ok := jwtToken.Header["kid"].(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrNoKid
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err = FindKey(kid)
|
||||||
|
if err != nil || key.ID == "" {
|
||||||
|
return nil, ErrKeyNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(key.Secret), nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return Token{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userid, permissions, err := parseClaims(jwtToken.Claims)
|
||||||
|
if err != nil {
|
||||||
|
return Token{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !key.ValidForUser(userid) {
|
||||||
|
return Token{}, ErrWrongUser
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := FindUser(userid)
|
||||||
|
if err != nil {
|
||||||
|
return Token{}, ErrDeletedUser
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, permission := range permissions {
|
||||||
|
found := false
|
||||||
|
|
||||||
|
for _, userPermission := range user.Permissions {
|
||||||
|
if permission == userPermission {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return Token{}, ErrWrongPermissions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Token{UserID: token.UserID, Permissions: permissions}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseClaims(jwtClaims jwt.Claims) (userid string, permissions []string, err error) {
|
||||||
|
mapClaims, ok := jwtClaims.(jwt.MapClaims)
|
||||||
|
if !ok {
|
||||||
|
return "", nil, ErrInvalidClaims
|
||||||
|
}
|
||||||
|
|
||||||
|
if !mapClaims.VerifyExpiresAt(time.Now().Unix(), true) {
|
||||||
|
return "", nil, ErrExpired
|
||||||
|
}
|
||||||
|
|
||||||
|
if userid, ok = mapClaims["user"].(string); !ok {
|
||||||
|
return "", nil, ErrInvalidClaims
|
||||||
|
}
|
||||||
|
|
||||||
|
if claimedPermissions, ok := mapClaims["permissions"].([]interface{}); ok {
|
||||||
|
for _, permission := range claimedPermissions {
|
||||||
|
if permission, ok := permission.(string); ok {
|
||||||
|
permissions = append(permissions, permission)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(permissions) == 0 {
|
||||||
|
return "", nil, ErrInvalidClaims
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package session
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.aiterp.net/rpdata/api/internal/store"
|
"git.aiterp.net/rpdata/api/internal/store"
|
||||||
@@ -16,7 +16,7 @@ type User struct {
|
|||||||
|
|
||||||
// Permitted returns true if either of the permissions can be found
|
// Permitted returns true if either of the permissions can be found
|
||||||
//
|
//
|
||||||
// `user.ID == page.Author || user.Permitted("story.edit")`
|
// `token.UserID == page.Author || token.Permitted("story.edit")`
|
||||||
func (user *User) Permitted(permissions ...string) bool {
|
func (user *User) Permitted(permissions ...string) bool {
|
||||||
for i := range permissions {
|
for i := range permissions {
|
||||||
for j := range user.Permissions {
|
for j := range user.Permissions {
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package session
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type contextKeyType struct{ name string }
|
|
||||||
|
|
||||||
func (ck *contextKeyType) String() string {
|
|
||||||
return ck.name
|
|
||||||
}
|
|
||||||
|
|
||||||
var contextKey = &contextKeyType{name: "session context key"}
|
|
||||||
|
|
||||||
// FromContext gets a session fron the context.
|
|
||||||
func FromContext(ctx context.Context) *Session {
|
|
||||||
return ctx.Value(contextKey).(*Session)
|
|
||||||
}
|
|
||||||
|
|
||||||
func contextWithSession(parent context.Context, session *Session) context.Context {
|
|
||||||
return context.WithValue(parent, contextKey, session)
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package session
|
|
||||||
|
|
||||||
// DefaultPermissions gets the default permissions
|
|
||||||
func DefaultPermissions() []string {
|
|
||||||
return []string{
|
|
||||||
"member",
|
|
||||||
"log.edit",
|
|
||||||
"log.reorder",
|
|
||||||
"post.edit",
|
|
||||||
"post.move",
|
|
||||||
"file.upload",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllPermissions gets all permissions and their purpose
|
|
||||||
func AllPermissions() map[string]string {
|
|
||||||
return map[string]string{
|
|
||||||
"member": "Can add/edit/remove own content",
|
|
||||||
"user.edit": "Can edit non-owned users",
|
|
||||||
"character.add": "Can add non-owned characters",
|
|
||||||
"character.edit": "Can edit non-owned characters",
|
|
||||||
"character.remove": "Can remove non-owned characters",
|
|
||||||
"channel.add": "Can add channels",
|
|
||||||
"channel.edit": "Can edit channels",
|
|
||||||
"channel.remove": "Can remove channels",
|
|
||||||
"log.add": "Can add logs",
|
|
||||||
"log.edit": "Can edit logs",
|
|
||||||
"log.remove": "Can remove logs",
|
|
||||||
"post.add": "Can add posts",
|
|
||||||
"post.edit": "Can edit posts",
|
|
||||||
"post.move": "Can move posts",
|
|
||||||
"post.remove": "Can remove posts",
|
|
||||||
"story.edit": "Can edit non-owned stories",
|
|
||||||
"story.remove": "Can remove non-owned stories",
|
|
||||||
"story.unlisted": "Can view unlisted stories by other users",
|
|
||||||
"file.upload": "Can upload files",
|
|
||||||
"file.edit": "Can edit non-owned files",
|
|
||||||
"file.remove": "Can remove non-owned files",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
package session
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/hex"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.aiterp.net/aiterp/wikiauth"
|
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/internal/config"
|
|
||||||
"git.aiterp.net/rpdata/api/internal/store"
|
|
||||||
"github.com/globalsign/mgo"
|
|
||||||
"github.com/globalsign/mgo/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
var sessionCollection *mgo.Collection
|
|
||||||
|
|
||||||
// A Session represents a login session.
|
|
||||||
type Session struct {
|
|
||||||
mutex sync.Mutex
|
|
||||||
|
|
||||||
ID string `bson:"_id"`
|
|
||||||
Time time.Time `bson:"time"`
|
|
||||||
UserID string `bson:"userId"`
|
|
||||||
|
|
||||||
user *User
|
|
||||||
w http.ResponseWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load loads a session from a cookie, returning either `r` or a request
|
|
||||||
// with the session context.
|
|
||||||
func Load(w http.ResponseWriter, r *http.Request) *http.Request {
|
|
||||||
cookie, err := r.Cookie("aiterp_session")
|
|
||||||
if err != nil {
|
|
||||||
return r.WithContext(contextWithSession(r.Context(), &Session{w: w}))
|
|
||||||
}
|
|
||||||
|
|
||||||
id := cookie.Value
|
|
||||||
|
|
||||||
session := Session{}
|
|
||||||
err = sessionCollection.FindId(id).One(&session)
|
|
||||||
if err != nil || time.Since(session.Time) > time.Hour*168 {
|
|
||||||
return r.WithContext(contextWithSession(r.Context(), &Session{w: w}))
|
|
||||||
}
|
|
||||||
|
|
||||||
if session.ID != "" && time.Since(session.Time) > time.Second*30 {
|
|
||||||
session.Time = time.Now()
|
|
||||||
go sessionCollection.UpdateId(id, bson.M{"$set": bson.M{"time": session.Time}})
|
|
||||||
}
|
|
||||||
|
|
||||||
cookie.Expires = time.Now().Add(time.Hour * 168)
|
|
||||||
http.SetCookie(w, cookie)
|
|
||||||
|
|
||||||
session.w = w
|
|
||||||
|
|
||||||
return r.WithContext(contextWithSession(r.Context(), &session))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Login logs a user in.
|
|
||||||
func (session *Session) Login(username, password string) error {
|
|
||||||
auth := wikiauth.New(config.Global().Wiki.URL)
|
|
||||||
|
|
||||||
err := auth.Login(username, password)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow bot passwords
|
|
||||||
username = strings.SplitN(username, "@", 2)[0]
|
|
||||||
|
|
||||||
data := make([]byte, 32)
|
|
||||||
_, err = rand.Read(data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
session.ID = hex.EncodeToString(data)
|
|
||||||
session.UserID = username
|
|
||||||
session.Time = time.Now()
|
|
||||||
|
|
||||||
err = sessionCollection.Insert(&session)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
http.SetCookie(session.w, &http.Cookie{
|
|
||||||
Name: "aiterp_session",
|
|
||||||
Value: session.ID,
|
|
||||||
Expires: time.Now().Add(time.Hour * 2160), // 90 days
|
|
||||||
HttpOnly: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
user, err := FindUser(session.UserID)
|
|
||||||
if err == mgo.ErrNotFound {
|
|
||||||
user = User{ID: username, Nick: "", Permissions: DefaultPermissions()}
|
|
||||||
|
|
||||||
err := userCollection.Insert(user)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logout logs out the session
|
|
||||||
func (session *Session) Logout() {
|
|
||||||
http.SetCookie(session.w, &http.Cookie{
|
|
||||||
Name: "aiterp_session",
|
|
||||||
Value: "",
|
|
||||||
Expires: time.Unix(0, 0),
|
|
||||||
HttpOnly: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
session.mutex.Lock()
|
|
||||||
session.user = nil
|
|
||||||
session.UserID = ""
|
|
||||||
session.ID = ""
|
|
||||||
session.mutex.Unlock()
|
|
||||||
|
|
||||||
sessionCollection.RemoveId(session.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// User gets the user information for the session.
|
|
||||||
func (session *Session) User() *User {
|
|
||||||
session.mutex.Lock()
|
|
||||||
defer session.mutex.Unlock()
|
|
||||||
|
|
||||||
if session.user != nil {
|
|
||||||
return session.user
|
|
||||||
}
|
|
||||||
|
|
||||||
if session.UserID == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := FindUser(session.UserID)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &user
|
|
||||||
}
|
|
||||||
|
|
||||||
// NameOrPermitted is a shorthand for checking the username OR permissions, e.g. to check
|
|
||||||
// if a logged in user can edit a certain post.
|
|
||||||
func (session *Session) NameOrPermitted(userid string, permissions ...string) bool {
|
|
||||||
if session.UserID == userid {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
user := session.User()
|
|
||||||
if user == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return user.Permitted()
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
store.HandleInit(func(db *mgo.Database) {
|
|
||||||
sessionCollection = db.C("core.sessions")
|
|
||||||
|
|
||||||
sessionCollection.EnsureIndexKey("nick")
|
|
||||||
sessionCollection.EnsureIndexKey("userId")
|
|
||||||
|
|
||||||
err := sessionCollection.EnsureIndex(mgo.Index{
|
|
||||||
Name: "time",
|
|
||||||
Key: []string{"time"},
|
|
||||||
ExpireAfter: time.Hour * 168,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user