From 39012c6b17073f6933a5ead8beed64df555f7348 Mon Sep 17 00:00:00 2001 From: FChannel <> Date: Fri, 6 May 2022 22:45:27 -0700 Subject: converting functions to activitypub object functions --- activitypub/activity.go | 2 +- activitypub/actor.go | 685 +++++++++++++++++++++++------------------------- db/database.go | 55 ++-- db/follow.go | 26 +- db/verification.go | 2 +- main.go | 122 +-------- routes/actor.go | 14 +- routes/admin.go | 6 +- routes/follow.go | 7 +- routes/index.go | 2 +- routes/outbox.go | 4 +- routes/post.go | 4 +- routes/util.go | 86 +++++- util/util.go | 41 +++ 14 files changed, 519 insertions(+), 537 deletions(-) diff --git a/activitypub/activity.go b/activitypub/activity.go index 22c9f06..9cf5bf2 100644 --- a/activitypub/activity.go +++ b/activitypub/activity.go @@ -36,7 +36,7 @@ func AcceptActivity(header string) bool { return accept } -func ActivitySign(actor Actor, signature string) (string, error) { +func (actor Actor) ActivitySign(signature string) (string, error) { query := `select file from publicKeyPem where id=$1 ` rows, err := config.DB.Query(query, actor.PublicKey.Id) diff --git a/activitypub/actor.go b/activitypub/actor.go index 757f6bf..4351a9b 100644 --- a/activitypub/actor.go +++ b/activitypub/actor.go @@ -39,10 +39,10 @@ func CreateNewActor(board string, prefName string, summary string, authReq []str return actor } -func DeleteActorCache(actorID string) error { +func (actor Actor) DeleteCache() error { query := `select id from cacheactivitystream where id in (select id from cacheactivitystream where actor=$1)` - rows, err := config.DB.Query(query, actorID) + rows, err := config.DB.Query(query, actor.Id) if err != nil { return err @@ -64,78 +64,24 @@ func DeleteActorCache(actorID string) error { return nil } -func GetActorAuth(actor string) ([]string, error) { - var auth []string - - query := `select type from actorauth where board=$1` - - rows, err := config.DB.Query(query, actor) - if err != nil { - return auth, err - } - defer rows.Close() - - for rows.Next() { - var e string - if err := rows.Scan(&e); err != nil { - return auth, err - } - - auth = append(auth, e) - } - - return auth, nil -} +func (actor Actor) GetAutoSubscribe() (bool, error) { + var subscribed bool -func GetActorAutoSubscribeDB(id string) (bool, error) { query := `select autosubscribe from actor where id=$1` - - rows, err := config.DB.Query(query, id) - if err != nil { + if err := config.DB.QueryRow(query, actor.Id).Scan(&subscribed); err != nil { return false, err } - var subscribed bool - defer rows.Close() - rows.Next() - err = rows.Scan(&subscribed) - return subscribed, err -} - -func GetActorByNameFromDB(name string) (Actor, error) { - var nActor Actor - - query := `select type, id, name, preferedusername, inbox, outbox, following, followers, restricted, summary, publickeypem from actor where name=$1` - - rows, err := config.DB.Query(query, name) - if err != nil { - return nActor, err - } - - var publicKeyPem string - defer rows.Close() - for rows.Next() { - if err := rows.Scan(&nActor.Type, &nActor.Id, &nActor.Name, &nActor.PreferredUsername, &nActor.Inbox, &nActor.Outbox, &nActor.Following, &nActor.Followers, &nActor.Restricted, &nActor.Summary, &publicKeyPem); err != nil { - return nActor, err - } - } - - if nActor.Id != "" && nActor.PublicKey.PublicKeyPem == "" { - if err := CreatePublicKeyFromPrivate(&nActor, publicKeyPem); err != nil { - return nActor, err - } - } - - return nActor, nil + return subscribed, nil } -func GetActorCollectionDBType(actorId string, nType string) (Collection, error) { +func (actor Actor) GetCollectionType(nType string) (Collection, error) { var nColl Collection var result []ObjectBase query := `select x.id, x.name, x.content, x.type, x.published, x.updated, x.attributedto, x.attachment, x.preview, x.actor, x.tripcode, x.sensitive from (select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where actor=$1 and id in (select id from replies where inreplyto='') and type=$2 union select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where actor in (select following from following where id=$1) and id in (select id from replies where inreplyto='') and type=$2 union select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from cacheactivitystream where actor in (select following from following where id=$1) and id in (select id from replies where inreplyto='') and type=$2) as x order by x.updated desc` - rows, err := config.DB.Query(query, actorId, nType) + rows, err := config.DB.Query(query, actor.Id, nType) if err != nil { return nColl, err } @@ -158,6 +104,7 @@ func GetActorCollectionDBType(actorId string, nType string) (Collection, error) post.Replies = &replies var err error + post.Replies.TotalItems, post.Replies.TotalImgs, err = GetObjectRepliesCount(post) if err != nil { return nColl, err @@ -181,13 +128,13 @@ func GetActorCollectionDBType(actorId string, nType string) (Collection, error) return nColl, nil } -func GetActorCollectionDBTypeLimit(actorId string, nType string, limit int) (Collection, error) { +func (actor Actor) GetCollectionTypeLimit(nType string, limit int) (Collection, error) { var nColl Collection var result []ObjectBase query := `select x.id, x.name, x.content, x.type, x.published, x.updated, x.attributedto, x.attachment, x.preview, x.actor, x.tripcode, x.sensitive from (select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where actor=$1 and id in (select id from replies where inreplyto='') and type=$2 union select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where actor in (select following from following where id=$1) and id in (select id from replies where inreplyto='') and type=$2 union select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from cacheactivitystream where actor in (select following from following where id=$1) and id in (select id from replies where inreplyto='') and type=$2) as x order by x.updated desc limit $3` - rows, err := config.DB.Query(query, actorId, nType, limit) + rows, err := config.DB.Query(query, actor.Id, nType, limit) if err != nil { return nColl, err } @@ -233,45 +180,12 @@ func GetActorCollectionDBTypeLimit(actorId string, nType string, limit int) (Col return nColl, nil } -func GetActorCollectionReq(collection string) (Collection, error) { - var nCollection Collection - - req, err := http.NewRequest("GET", collection, nil) - if err != nil { - return nCollection, err - } - - // TODO: rewrite this for fiber - pass := "FIXME" - //_, pass := GetPasswordFromSession(r) - - req.Header.Set("Accept", config.ActivityStreams) - - req.Header.Set("Authorization", "Basic "+pass) - - resp, err := util.RouteProxy(req) - if err != nil { - return nCollection, err - } - defer resp.Body.Close() - - if resp.StatusCode == 200 { - body, _ := ioutil.ReadAll(resp.Body) - - if err := json.Unmarshal(body, &nCollection); err != nil { - return nCollection, err - } - } - - return nCollection, nil -} - -func GetActorFollowDB(id string) ([]ObjectBase, error) { +func (actor Actor) GetFollow() ([]ObjectBase, error) { var followerCollection []ObjectBase query := `select follower from follower where id=$1` - rows, err := config.DB.Query(query, id) + rows, err := config.DB.Query(query, actor.Id) if err != nil { return followerCollection, err } @@ -290,67 +204,40 @@ func GetActorFollowDB(id string) ([]ObjectBase, error) { return followerCollection, nil } -func GetActorFollowNameFromPath(path string) string { - var actor string - - re := regexp.MustCompile("f\\w+-") - - actor = re.FindString(path) - - actor = strings.Replace(actor, "f", "", 1) - actor = strings.Replace(actor, "-", "", 1) - - return actor -} - -func GetActorFollowTotal(id string) (int, int, error) { +func (actor Actor) GetFollowingTotal() (int, error) { var following int - var followers int query := `select count(following) from following where id=$1` - - rows, err := config.DB.Query(query, id) - if err != nil { - return 0, 0, err - } - defer rows.Close() - - for rows.Next() { - if err := rows.Scan(&following); err != nil { - return following, 0, err - } + if err := config.DB.QueryRow(query, actor.Id).Scan(&following); err != nil { + return following, err } - query = `select count(follower) from follower where id=$1` - - rows, err = config.DB.Query(query, id) - if err != nil { - return 0, 0, err - } - defer rows.Close() + return following, nil +} - for rows.Next() { - if err := rows.Scan(&followers); err != nil { - return following, followers, err - } +func (actor Actor) GetFollowersTotal() (int, error) { + var followers int + query := `select count(follower) from follower where id=$1` + if err := config.DB.QueryRow(query, actor.Id).Scan(&followers); err != nil { + return followers, err } - return following, followers, nil + return followers, nil } -func GetActorFollowers(ctx *fiber.Ctx, id string) error { +func (actor Actor) GetFollowersResp(ctx *fiber.Ctx) error { var following Collection var err error following.AtContext.Context = "https://www.w3.org/ns/activitystreams" following.Type = "Collection" - _, following.TotalItems, err = GetActorFollowTotal(id) + following.TotalItems, err = actor.GetFollowingTotal() if err != nil { return err } - following.Items, err = GetActorFollowDB(id) + following.Items, err = actor.GetFollow() if err != nil { return err } @@ -361,18 +248,18 @@ func GetActorFollowers(ctx *fiber.Ctx, id string) error { return err } -func GetActorFollowing(ctx *fiber.Ctx, id string) error { +func (actor Actor) GetFollowingResp(ctx *fiber.Ctx) error { var following Collection var err error following.AtContext.Context = "https://www.w3.org/ns/activitystreams" following.Type = "Collection" - following.TotalItems, _, err = GetActorFollowTotal(id) + following.TotalItems, err = actor.GetFollowingTotal() if err != nil { return err } - following.Items, err = GetActorFollowingDB(id) + following.Items, err = actor.GetFollowing() if err != nil { return err } @@ -384,11 +271,11 @@ func GetActorFollowing(ctx *fiber.Ctx, id string) error { return err } -func GetActorFollowingDB(id string) ([]ObjectBase, error) { +func (actor Actor) GetFollowing() ([]ObjectBase, error) { var followingCollection []ObjectBase query := `select following from following where id=$1` - rows, err := config.DB.Query(query, id) + rows, err := config.DB.Query(query, actor.Id) if err != nil { return followingCollection, err } @@ -407,116 +294,22 @@ func GetActorFollowingDB(id string) ([]ObjectBase, error) { return followingCollection, nil } -func GetActorFromDB(id string) (Actor, error) { - var nActor Actor - - query := `select type, id, name, preferedusername, inbox, outbox, following, followers, restricted, summary, publickeypem from actor where id=$1` - - var publicKeyPem string - err := config.DB.QueryRow(query, id).Scan(&nActor.Type, &nActor.Id, &nActor.Name, &nActor.PreferredUsername, &nActor.Inbox, &nActor.Outbox, &nActor.Following, &nActor.Followers, &nActor.Restricted, &nActor.Summary, &publicKeyPem) - if err != nil { - return nActor, err - } - - nActor.PublicKey, err = GetActorPemFromDB(publicKeyPem) - if err != nil { - return nActor, err - } - - if nActor.Id != "" && nActor.PublicKey.PublicKeyPem == "" { - if err := CreatePublicKeyFromPrivate(&nActor, publicKeyPem); err != nil { - return nActor, err - } - } - - return nActor, nil -} - -func GetActorFromJson(actor []byte) (Actor, error) { - var generic interface{} - var nActor Actor - err := json.Unmarshal(actor, &generic) - if err != nil { - return nActor, err - } - - if generic != nil { - switch generic.(type) { - case map[string]interface{}: - err = json.Unmarshal(actor, &nActor) - break - - case string: - var str string - err = json.Unmarshal(actor, &str) - nActor.Id = str - break - } - - return nActor, err - } - - return nActor, nil -} - -func GetActorInfo(ctx *fiber.Ctx, id string) error { - actor, err := GetActorFromDB(id) - if err != nil { - return err - } - +func (actor Actor) GetInfoResp(ctx *fiber.Ctx) error { enc, _ := json.MarshalIndent(actor, "", "\t") ctx.Response().Header.Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") - _, err = ctx.Write(enc) + _, err := ctx.Write(enc) return err } -func GetActorInstance(path string) (string, string) { - re := regexp.MustCompile(`([@]?([\w\d.-_]+)[@](.+))`) - atFormat := re.MatchString(path) - - if atFormat { - match := re.FindStringSubmatch(path) - if len(match) > 2 { - return match[2], match[3] - } - } - - re = regexp.MustCompile(`(https?://)(www)?([\w\d-_.:]+)(/|\s+|\r|\r\n)?$`) - mainActor := re.MatchString(path) - if mainActor { - match := re.FindStringSubmatch(path) - if len(match) > 2 { - return "main", match[3] - } - } - - re = regexp.MustCompile(`(https?://)?(www)?([\w\d-_.:]+)\/([\w\d-_.]+)(\/([\w\d-_.]+))?`) - httpFormat := re.MatchString(path) - - if httpFormat { - match := re.FindStringSubmatch(path) - if len(match) > 3 { - if match[4] == "users" { - return match[6], match[3] - } - - return match[4], match[3] - } - } - - return "", "" -} - -func GetActorObjectCollectionFromDB(actorId string) (Collection, error) { +func (actor Actor) GetCollection() (Collection, error) { var nColl Collection var result []ObjectBase query := `select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where actor=$1 and id in (select id from replies where inreplyto='') and type='Note' order by updated desc` - rows, err := config.DB.Query(query, actorId) + rows, err := config.DB.Query(query, actor.Id) if err != nil { return nColl, err } @@ -562,12 +355,12 @@ func GetActorObjectCollectionFromDB(actorId string) (Collection, error) { return nColl, nil } -func GetActorReportedDB(id string) ([]ObjectBase, error) { +func (actor Actor) GetReported() ([]ObjectBase, error) { var nObj []ObjectBase query := `select id, count, reason from reported where board=$1` - rows, err := config.DB.Query(query, id) + rows, err := config.DB.Query(query, actor.Id) if err != nil { return nObj, err } @@ -585,69 +378,24 @@ func GetActorReportedDB(id string) ([]ObjectBase, error) { return nObj, nil } -func GetActorReportedTotal(id string) (int, error) { - query := `select count(id) from reported where board=$1` +func (actor Actor) GetReportedTotal() (int, error) { + var count int - rows, err := config.DB.Query(query, id) - if err != nil { + query := `select count(id) from reported where board=$1` + if err := config.DB.QueryRow(query, actor.Id).Scan(&count); err != nil { return 0, err } - defer rows.Close() - - var count int - for rows.Next() { - rows.Scan(&count) - } - return count, nil } -func GetActorsFollowPostFromId(actors []string, id string) (Collection, error) { - var collection Collection - - for _, e := range actors { - tempCol, err := GetObjectByIDFromDB(e + "/" + id) - if err != nil { - return collection, err - } - - if len(tempCol.OrderedItems) > 0 { - collection = tempCol - return collection, nil - } - } - - return collection, nil -} - -func GetActorPost(ctx *fiber.Ctx, path string) error { - collection, err := GetCollectionFromPath(config.Domain + "" + path) - if err != nil { - return err - } - - if len(collection.OrderedItems) > 0 { - enc, err := json.MarshalIndent(collection, "", "\t") - if err != nil { - return err - } - - ctx.Response().Header.Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") - _, err = ctx.Write(enc) - return err - } - - return nil -} - -func GetAllActorArchiveDB(id string, offset int) (Collection, error) { +func (actor Actor) GetAllArchive(offset int) (Collection, error) { var nColl Collection var result []ObjectBase query := `select x.id, x.updated from (select id, updated from activitystream where actor=$1 and id in (select id from replies where inreplyto='') and type='Note' union select id, updated from activitystream where actor in (select following from following where id=$1) and id in (select id from replies where inreplyto='') and type='Note' union select id, updated from cacheactivitystream where actor in (select following from following where id=$1) and id in (select id from replies where inreplyto='') and type='Note') as x order by x.updated desc offset $2` - rows, err := config.DB.Query(query, id, offset) + rows, err := config.DB.Query(query, actor.Id, offset) if err != nil { return nColl, err } @@ -670,37 +418,23 @@ func GetAllActorArchiveDB(id string, offset int) (Collection, error) { return nColl, nil } -func GetBoards() ([]Actor, error) { - var boards []Actor - - query := `select type, id, name, preferedusername, inbox, outbox, following, followers FROM actor` - - rows, err := config.DB.Query(query) +func (actor Actor) IsAlreadyFollowing(follow string) (bool, error) { + followers, err := actor.GetFollowing() if err != nil { - return boards, err + return false, err } - defer rows.Close() - for rows.Next() { - var actor = new(Actor) - - if err := rows.Scan(&actor.Type, &actor.Id, &actor.Name, &actor.PreferredUsername, &actor.Inbox, &actor.Outbox, &actor.Following, &actor.Followers); err != nil { - return boards, err + for _, e := range followers { + if e.Id == follow { + return true, nil } - - boards = append(boards, *actor) } - return boards, nil -} - -func IsActorLocal(id string) (bool, error) { - actor, err := GetActorFromDB(id) - return actor.Id != "", err + return false, nil } -func IsAlreadyFollowing(actor string, follow string) (bool, error) { - followers, err := GetActorFollowingDB(actor) +func (actor Actor) IsAlreadyFollower(follow string) (bool, error) { + followers, err := actor.GetFollow() if err != nil { return false, err } @@ -714,36 +448,293 @@ func IsAlreadyFollowing(actor string, follow string) (bool, error) { return false, nil } -func IsAlreadyFollower(actor string, follow string) (bool, error) { - followers, err := GetActorFollowDB(actor) +func (actor Actor) SetActorAutoSubscribeDB() error { + current, err := actor.GetAutoSubscribe() if err != nil { - return false, err + return err } - for _, e := range followers { - if e.Id == follow { - return true, nil + query := `update actor set autosubscribe=$1 where id=$2` + + _, err = config.DB.Exec(query, !current, actor.Id) + return err +} + +func (actor Actor) GetOutbox(ctx *fiber.Ctx) error { + + var collection Collection + + c, err := actor.GetCollection() + if err != nil { + return err + } + collection.OrderedItems = c.OrderedItems + + collection.AtContext.Context = "https://www.w3.org/ns/activitystreams" + collection.Actor = &actor + + collection.TotalItems, err = GetObjectPostsTotalDB(actor) + if err != nil { + return err + } + + collection.TotalImgs, err = GetObjectImgsTotalDB(actor) + if err != nil { + return err + } + + enc, _ := json.Marshal(collection) + + ctx.Response().Header.Set("Content-Type", config.ActivityStreams) + _, err = ctx.Write(enc) + return err +} + +func (actor Actor) UnArchiveLast() error { + col, err := actor.GetCollectionTypeLimit("Archive", 1) + if err != nil { + return err + } + + for _, e := range col.OrderedItems { + for _, k := range e.Replies.OrderedItems { + if err := UpdateObjectTypeDB(k.Id, "Note"); err != nil { + return err + } + } + + if err := UpdateObjectTypeDB(e.Id, "Note"); err != nil { + return err } } - return false, nil + return nil +} + +func GetActorByNameFromDB(name string) (Actor, error) { + var nActor Actor + var publicKeyPem string + + query := `select type, id, name, preferedusername, inbox, outbox, following, followers, restricted, summary, publickeypem from actor where name=$1` + err := config.DB.QueryRow(query, name).Scan(&nActor.Type, &nActor.Id, &nActor.Name, &nActor.PreferredUsername, &nActor.Inbox, &nActor.Outbox, &nActor.Following, &nActor.Followers, &nActor.Restricted, &nActor.Summary, &publicKeyPem) + if err != nil { + return nActor, err + } + + if nActor.Id != "" && nActor.PublicKey.PublicKeyPem == "" { + if err := CreatePublicKeyFromPrivate(&nActor, publicKeyPem); err != nil { + return nActor, err + } + } + + return nActor, nil +} + +func GetActorCollectionReq(collection string) (Collection, error) { + var nCollection Collection + + req, err := http.NewRequest("GET", collection, nil) + if err != nil { + return nCollection, err + } + + // TODO: rewrite this for fiber + pass := "FIXME" + //_, pass := GetPasswordFromSession(r) + + req.Header.Set("Accept", config.ActivityStreams) + + req.Header.Set("Authorization", "Basic "+pass) + + resp, err := util.RouteProxy(req) + if err != nil { + return nCollection, err + } + defer resp.Body.Close() + + if resp.StatusCode == 200 { + body, _ := ioutil.ReadAll(resp.Body) + + if err := json.Unmarshal(body, &nCollection); err != nil { + return nCollection, err + } + } + + return nCollection, nil +} + +func GetActorFollowNameFromPath(path string) string { + var actor string + + re := regexp.MustCompile("f\\w+-") + + actor = re.FindString(path) + + actor = strings.Replace(actor, "f", "", 1) + actor = strings.Replace(actor, "-", "", 1) + + return actor +} + +func GetActorFromDB(id string) (Actor, error) { + var nActor Actor + + query := `select type, id, name, preferedusername, inbox, outbox, following, followers, restricted, summary, publickeypem from actor where id=$1` + + var publicKeyPem string + err := config.DB.QueryRow(query, id).Scan(&nActor.Type, &nActor.Id, &nActor.Name, &nActor.PreferredUsername, &nActor.Inbox, &nActor.Outbox, &nActor.Following, &nActor.Followers, &nActor.Restricted, &nActor.Summary, &publicKeyPem) + if err != nil { + return nActor, err + } + + nActor.PublicKey, err = GetActorPemFromDB(publicKeyPem) + if err != nil { + return nActor, err + } + + if nActor.Id != "" && nActor.PublicKey.PublicKeyPem == "" { + if err := CreatePublicKeyFromPrivate(&nActor, publicKeyPem); err != nil { + return nActor, err + } + } + + return nActor, nil } -func SetActorAutoSubscribeDB(id string) error { - current, err := GetActorAutoSubscribeDB(id) +func GetActorFromJson(actor []byte) (Actor, error) { + var generic interface{} + var nActor Actor + err := json.Unmarshal(actor, &generic) + if err != nil { + return nActor, err + } + + if generic != nil { + switch generic.(type) { + case map[string]interface{}: + err = json.Unmarshal(actor, &nActor) + break + + case string: + var str string + err = json.Unmarshal(actor, &str) + nActor.Id = str + break + } + + return nActor, err + } + + return nActor, nil +} + +func GetActorInstance(path string) (string, string) { + re := regexp.MustCompile(`([@]?([\w\d.-_]+)[@](.+))`) + atFormat := re.MatchString(path) + + if atFormat { + match := re.FindStringSubmatch(path) + if len(match) > 2 { + return match[2], match[3] + } + } + + re = regexp.MustCompile(`(https?://)(www)?([\w\d-_.:]+)(/|\s+|\r|\r\n)?$`) + mainActor := re.MatchString(path) + if mainActor { + match := re.FindStringSubmatch(path) + if len(match) > 2 { + return "main", match[3] + } + } + + re = regexp.MustCompile(`(https?://)?(www)?([\w\d-_.:]+)\/([\w\d-_.]+)(\/([\w\d-_.]+))?`) + httpFormat := re.MatchString(path) + + if httpFormat { + match := re.FindStringSubmatch(path) + if len(match) > 3 { + if match[4] == "users" { + return match[6], match[3] + } + + return match[4], match[3] + } + } + + return "", "" +} + +func GetActorsFollowPostFromId(actors []string, id string) (Collection, error) { + var collection Collection + + for _, e := range actors { + tempCol, err := GetObjectByIDFromDB(e + "/" + id) + if err != nil { + return collection, err + } + + if len(tempCol.OrderedItems) > 0 { + collection = tempCol + return collection, nil + } + } + + return collection, nil +} + +func GetActorPost(ctx *fiber.Ctx, path string) error { + collection, err := GetCollectionFromPath(config.Domain + "" + path) if err != nil { return err } - query := `update actor set autosubscribe=$1 where id=$2` + if len(collection.OrderedItems) > 0 { + enc, err := json.MarshalIndent(collection, "", "\t") + if err != nil { + return err + } - _, err = config.DB.Exec(query, !current, id) - return err + ctx.Response().Header.Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") + _, err = ctx.Write(enc) + return err + } + + return nil +} + +func GetBoards() ([]Actor, error) { + var boards []Actor + + query := `select type, id, name, preferedusername, inbox, outbox, following, followers FROM actor` + + rows, err := config.DB.Query(query) + if err != nil { + return boards, err + } + + defer rows.Close() + for rows.Next() { + var actor = new(Actor) + + if err := rows.Scan(&actor.Type, &actor.Id, &actor.Name, &actor.PreferredUsername, &actor.Inbox, &actor.Outbox, &actor.Following, &actor.Followers); err != nil { + return boards, err + } + + boards = append(boards, *actor) + } + + return boards, nil +} + +func IsActorLocal(id string) (bool, error) { + actor, err := GetActorFromDB(id) + return actor.Id != "", err } func SetActorFollowerDB(activity Activity) (Activity, error) { var query string - alreadyFollow, err := IsAlreadyFollower(activity.Actor.Id, activity.Object.Actor) + alreadyFollow, err := activity.Actor.IsAlreadyFollower(activity.Object.Actor) if err != nil { return activity, err } @@ -863,33 +854,3 @@ func WriteActorObjectToCache(obj ObjectBase) (ObjectBase, error) { return obj, nil } - -func GetActorOutbox(ctx *fiber.Ctx, actor Actor) error { - - var collection Collection - - c, err := GetActorObjectCollectionFromDB(actor.Id) - if err != nil { - return err - } - collection.OrderedItems = c.OrderedItems - - collection.AtContext.Context = "https://www.w3.org/ns/activitystreams" - collection.Actor = &actor - - collection.TotalItems, err = GetObjectPostsTotalDB(actor) - if err != nil { - return err - } - - collection.TotalImgs, err = GetObjectImgsTotalDB(actor) - if err != nil { - return err - } - - enc, _ := json.Marshal(collection) - - ctx.Response().Header.Set("Content-Type", config.ActivityStreams) - _, err = ctx.Write(enc) - return err -} diff --git a/db/database.go b/db/database.go index eb0bb98..4c97fe5 100644 --- a/db/database.go +++ b/db/database.go @@ -388,7 +388,7 @@ func IsInactiveTimestamp(timeStamp string) bool { func ArchivePosts(actor activitypub.Actor) error { if actor.Id != "" && actor.Id != config.Domain { - col, err := activitypub.GetAllActorArchiveDB(actor.Id, 165) + col, err := actor.GetAllArchive(165) if err != nil { return err } @@ -409,27 +409,6 @@ func ArchivePosts(actor activitypub.Actor) error { return nil } -func UnArchiveLast(actorId string) error { - col, err := activitypub.GetActorCollectionDBTypeLimit(actorId, "Archive", 1) - if err != nil { - return err - } - - for _, e := range col.OrderedItems { - for _, k := range e.Replies.OrderedItems { - if err := activitypub.UpdateObjectTypeDB(k.Id, "Note"); err != nil { - return err - } - } - - if err := activitypub.UpdateObjectTypeDB(e.Id, "Note"); err != nil { - return err - } - } - - return nil -} - func IsReplyInThread(inReplyTo string, id string) (bool, error) { obj, _, err := webfinger.CheckValidActivity(inReplyTo) if err != nil { @@ -628,17 +607,19 @@ func GetActorReported(w http.ResponseWriter, r *http.Request, id string) error { return err } + actor, _ := activitypub.GetActorFromDB(id) + var following activitypub.Collection var err error following.AtContext.Context = "https://www.w3.org/ns/activitystreams" following.Type = "Collection" - following.TotalItems, err = activitypub.GetActorReportedTotal(id) + following.TotalItems, err = actor.GetReportedTotal() if err != nil { return err } - following.Items, err = activitypub.GetActorReportedDB(id) + following.Items, err = actor.GetReported() if err != nil { return err } @@ -686,8 +667,8 @@ func DeleteObjectRequest(id string) error { return err } activity.Actor = &actor - - followers, err := activitypub.GetActorFollowDB(obj.Actor) + objActor, _ := webfinger.GetActor(obj.Actor) + followers, err := objActor.GetFollow() if err != nil { return err } @@ -696,7 +677,7 @@ func DeleteObjectRequest(id string) error { activity.To = append(activity.To, e.Id) } - following, err := activitypub.GetActorFollowingDB(obj.Actor) + following, err := objActor.GetFollowing() if err != nil { return err } @@ -727,7 +708,8 @@ func DeleteObjectAndRepliesRequest(id string) error { activity.Object = &obj.OrderedItems[0] - followers, err := activitypub.GetActorFollowDB(obj.OrderedItems[0].Actor) + objActor, _ := webfinger.GetActor(obj.OrderedItems[0].Actor) + followers, err := objActor.GetFollow() if err != nil { return err } @@ -735,7 +717,7 @@ func DeleteObjectAndRepliesRequest(id string) error { activity.To = append(activity.To, e.Id) } - following, err := activitypub.GetActorFollowingDB(obj.OrderedItems[0].Actor) + following, err := objActor.GetFollowing() if err != nil { return err } @@ -746,3 +728,18 @@ func DeleteObjectAndRepliesRequest(id string) error { return MakeActivityRequest(activity) } + +// root actor is used to follow remote feeds that are not local +//name, prefname, summary, auth requirements, restricted +func InitInstance() { + if config.InstanceName != "" { + if _, err := CreateNewBoardDB(*activitypub.CreateNewActor("", config.InstanceName, config.InstanceSummary, config.AuthReq, false)); err != nil { + //panic(err) + } + + if config.PublicIndexing == "true" { + // TODO: comment out later + //AddInstanceToIndex(config.Domain) + } + } +} diff --git a/db/follow.go b/db/follow.go index 3f7868d..e3c0583 100644 --- a/db/follow.go +++ b/db/follow.go @@ -40,7 +40,8 @@ func SetActorFollowingDB(activity activitypub.Activity) (activitypub.Activity, e var query string alreadyFollowing := false alreadyFollower := false - following, err := activitypub.GetActorFollowingDB(activity.Object.Actor) + objActor, _ := webfinger.GetActor(activity.Object.Actor) + following, err := objActor.GetFollowing() if err != nil { return activity, err } @@ -77,7 +78,7 @@ func SetActorFollowingDB(activity activitypub.Activity) (activitypub.Activity, e query = `delete from following where id=$1 and following=$2` activity.Summary = activity.Object.Actor + " Unfollowing " + activity.Actor.Id if res, err := activitypub.IsActorLocal(activity.Actor.Id); err == nil && !res { - go activitypub.DeleteActorCache(activity.Actor.Id) + go activity.Actor.DeleteCache() } else { return activity, err } @@ -108,13 +109,14 @@ func SetActorFollowingDB(activity activitypub.Activity) (activitypub.Activity, e return activity, nil } -func AutoFollow(actor string) error { - following, err := activitypub.GetActorFollowingDB(actor) +func AutoFollow(actorID string) error { + actor, _ := webfinger.GetActor(actorID) + following, err := actor.GetFollowing() if err != nil { return err } - follower, err := activitypub.GetActorFollowDB(actor) + follower, err := actor.GetFollow() if err != nil { return err } @@ -128,8 +130,8 @@ func AutoFollow(actor string) error { } } - if !isFollowing && e.Id != config.Domain && e.Id != actor { - followActivity, err := MakeFollowActivity(actor, e.Id) + if !isFollowing && e.Id != config.Domain && e.Id != actor.Id { + followActivity, err := MakeFollowActivity(actor.Id, e.Id) if err != nil { return err } @@ -204,7 +206,7 @@ func MakeActivityRequestOutbox(activity activitypub.Activity) error { path = re.ReplaceAllString(path, "") sig := fmt.Sprintf("(request-target): %s %s\nhost: %s\ndate: %s", "post", path, instance, date) - encSig, err := activitypub.ActivitySign(*activity.Actor, sig) + encSig, err := activity.Actor.ActivitySign(sig) if err != nil { return err } @@ -246,7 +248,7 @@ func MakeActivityRequest(activity activitypub.Activity) error { path = re.ReplaceAllString(path, "") sig := fmt.Sprintf("(request-target): %s %s\nhost: %s\ndate: %s", "post", path, instance, date) - encSig, err := activitypub.ActivitySign(*activity.Actor, sig) + encSig, err := activity.Actor.ActivitySign(sig) if err != nil { return err } @@ -271,15 +273,15 @@ func MakeActivityRequest(activity activitypub.Activity) error { return nil } -func SendToFollowers(actor string, activity activitypub.Activity) error { - nActor, err := activitypub.GetActorFromDB(actor) +func SendToFollowers(actorID string, activity activitypub.Activity) error { + nActor, err := activitypub.GetActorFromDB(actorID) if err != nil { return err } activity.Actor = &nActor - followers, err := activitypub.GetActorFollowDB(actor) + followers, err := nActor.GetFollow() if err != nil { return err } diff --git a/db/verification.go b/db/verification.go index a178d52..eea22ea 100644 --- a/db/verification.go +++ b/db/verification.go @@ -464,7 +464,7 @@ func HasBoardAccess(verify Verify) (bool, error) { } func BoardHasAuthType(board string, auth string) (bool, error) { - authTypes, err := activitypub.GetActorAuth(board) + authTypes, err := util.GetBoardAuth(board) if err != nil { return false, err } diff --git a/main.go b/main.go index 90d7f13..c1ebcef 100644 --- a/main.go +++ b/main.go @@ -1,20 +1,13 @@ package main import ( - "fmt" - "html/template" - "io/ioutil" "log" "math/rand" - "path" - "regexp" - "strings" "time" "github.com/FChannel0/FChannel-Server/activitypub" "github.com/FChannel0/FChannel-Server/config" "github.com/FChannel0/FChannel-Server/db" - "github.com/FChannel0/FChannel-Server/post" "github.com/FChannel0/FChannel-Server/routes" "github.com/FChannel0/FChannel-Server/util" "github.com/FChannel0/FChannel-Server/webfinger" @@ -36,7 +29,7 @@ func main() { template := html.New("./views", ".html") template.Debug(true) - TemplateFunctions(template) + routes.TemplateFunctions(template) app := fiber.New(fiber.Config{ AppName: "FChannel", @@ -124,125 +117,28 @@ func Init() { db.RunDatabaseSchema() - go db.MakeCaptchas(100) - - config.Key = util.CreateKey(32) - - webfinger.FollowingBoards, err = activitypub.GetActorFollowingDB(config.Domain) + actor, _ := activitypub.GetActorFromDB(config.Domain) + webfinger.FollowingBoards, err = actor.GetFollowing() if err != nil { panic(err) } - go db.StartupArchive() - - go db.CheckInactive() - webfinger.Boards, err = webfinger.GetBoardCollection() if err != nil { panic(err) } - // root actor is used to follow remote feeds that are not local - //name, prefname, summary, auth requirements, restricted - if config.InstanceName != "" { - if _, err = db.CreateNewBoardDB(*activitypub.CreateNewActor("", config.InstanceName, config.InstanceSummary, config.AuthReq, false)); err != nil { - //panic(err) - } - - if config.PublicIndexing == "true" { - // TODO: comment out later - //AddInstanceToIndex(config.Domain) - } - } - - // get list of themes - themes, err := ioutil.ReadDir("./static/css/themes") - if err != nil { - panic(err) - } - - for _, f := range themes { - if e := path.Ext(f.Name()); e == ".css" { - config.Themes = append(config.Themes, strings.TrimSuffix(f.Name(), e)) - } - } -} - -func TemplateFunctions(engine *html.Engine) { - engine.AddFunc("mod", func(i, j int) bool { - return i%j == 0 - }) - - engine.AddFunc("sub", func(i, j int) int { - return i - j - }) - - engine.AddFunc("add", func(i, j int) int { - return i + j - }) - - engine.AddFunc("unixtoreadable", func(u int) string { - return time.Unix(int64(u), 0).Format("Jan 02, 2006") - }) - - engine.AddFunc("timeToReadableLong", func(t time.Time) string { - return t.Format("01/02/06(Mon)15:04:05") - }) - - engine.AddFunc("timeToUnix", func(t time.Time) string { - return fmt.Sprint(t.Unix()) - }) - - engine.AddFunc("proxy", util.MediaProxy) - - // previously short - engine.AddFunc("shortURL", util.ShortURL) - - engine.AddFunc("parseAttachment", post.ParseAttachment) - - engine.AddFunc("parseContent", post.ParseContent) - - engine.AddFunc("shortImg", util.ShortImg) - - engine.AddFunc("convertSize", util.ConvertSize) - - engine.AddFunc("isOnion", util.IsOnion) - - engine.AddFunc("parseReplyLink", func(actorId string, op string, id string, content string) template.HTML { - actor, _ := webfinger.FingerActor(actorId) - title := strings.ReplaceAll(post.ParseLinkTitle(actor.Id+"/", op, content), `/\<`, ">") - link := ">>" + util.ShortURL(actor.Outbox, id) + "" - return template.HTML(link) - }) - - engine.AddFunc("shortExcerpt", func(post activitypub.ObjectBase) string { - var returnString string - - if post.Name != "" { - returnString = post.Name + "| " + post.Content - } else { - returnString = post.Content - } - - re := regexp.MustCompile(`(^(.|\r\n|\n){100})`) - - match := re.FindStringSubmatch(returnString) + config.Key = util.CreateKey(32) - if len(match) > 0 { - returnString = match[0] + "..." - } + go db.MakeCaptchas(100) - re = regexp.MustCompile(`(^.+\|)`) + go db.StartupArchive() - match = re.FindStringSubmatch(returnString) + go db.CheckInactive() - if len(match) > 0 { - returnString = strings.Replace(returnString, match[0], ""+match[0]+"", 1) - returnString = strings.Replace(returnString, "|", ":", 1) - } + db.InitInstance() - return returnString - }) + util.LoadThemes() } diff --git a/routes/actor.go b/routes/actor.go index 5cd0fa9..ea8656f 100644 --- a/routes/actor.go +++ b/routes/actor.go @@ -95,7 +95,7 @@ func ActorInbox(ctx *fiber.Ctx) error { if err := activitypub.TombstoneObject(activity.Object.Id); err != nil { return err } - if err := db.UnArchiveLast(actor.Id); err != nil { + if err := actor.UnArchiveLast(); err != nil { return err } break @@ -118,12 +118,12 @@ func ActorInbox(ctx *fiber.Ctx) error { alreadyFollow := false alreadyFollowing := false - autoSub, err := activitypub.GetActorAutoSubscribeDB(response.Actor.Id) + autoSub, err := response.Actor.GetAutoSubscribe() if err != nil { return err } - following, err := activitypub.GetActorFollowingDB(response.Actor.Id) + following, err := response.Actor.GetFollowing() if err != nil { return err } @@ -195,7 +195,7 @@ func ActorOutbox(ctx *fiber.Ctx) error { } if activitypub.AcceptActivity(ctx.Get("Accept")) { - activitypub.GetActorOutbox(ctx, actor) + actor.GetOutbox(ctx) return nil } @@ -203,11 +203,13 @@ func ActorOutbox(ctx *fiber.Ctx) error { } func ActorFollowing(ctx *fiber.Ctx) error { - return activitypub.GetActorFollowing(ctx, config.Domain+"/"+ctx.Params("actor")) + actor, _ := activitypub.GetActorFromDB(config.Domain + "/" + ctx.Params("actor")) + return actor.GetFollowingResp(ctx) } func ActorFollowers(ctx *fiber.Ctx) error { - return activitypub.GetActorFollowers(ctx, config.Domain+"/"+ctx.Params("actor")) + actor, _ := activitypub.GetActorFromDB(config.Domain + "/" + ctx.Params("actor")) + return actor.GetFollowersResp(ctx) } func ActorReported(c *fiber.Ctx) error { diff --git a/routes/admin.go b/routes/admin.go index 771cda2..ea27792 100644 --- a/routes/admin.go +++ b/routes/admin.go @@ -160,7 +160,7 @@ func AdminFollow(ctx *fiber.Ctx) error { col.Items = append(col.Items, nObj) for _, e := range col.Items { - if isFollowing, _ := activitypub.IsAlreadyFollowing(actorId, e.Id); !isFollowing && e.Id != config.Domain && e.Id != actorId { + if isFollowing, _ := actor.IsAlreadyFollowing(e.Id); !isFollowing && e.Id != config.Domain && e.Id != actorId { followActivity, _ := db.MakeFollowActivity(actorId, e.Id) if actor, _ := webfinger.FingerActor(e.Id); actor.Id != "" { @@ -180,7 +180,7 @@ func AdminFollow(ctx *fiber.Ctx) error { col.Items = append(col.Items, nObj) for _, e := range col.Items { - if isFollowing, _ := activitypub.IsAlreadyFollowing(actorId, e.Id); !isFollowing && e.Id != config.Domain && e.Id != actorId { + if isFollowing, _ := actor.IsAlreadyFollowing(e.Id); !isFollowing && e.Id != config.Domain && e.Id != actorId { followActivity, _ := db.MakeFollowActivity(actorId, e.Id) if actor, _ := webfinger.FingerActor(e.Id); actor.Id != "" { db.MakeActivityRequestOutbox(followActivity) @@ -314,7 +314,7 @@ func AdminActorIndex(ctx *fiber.Ctx) error { data.Board.Post.Actor = actor.Id - data.AutoSubscribe, _ = activitypub.GetActorAutoSubscribeDB(actor.Id) + data.AutoSubscribe, _ = actor.GetAutoSubscribe() data.Themes = &config.Themes diff --git a/routes/follow.go b/routes/follow.go index 3dbf9cf..f61e405 100644 --- a/routes/follow.go +++ b/routes/follow.go @@ -7,10 +7,11 @@ import ( ) func Following(ctx *fiber.Ctx) error { - return activitypub.GetActorFollowing(ctx, config.Domain) + actor, _ := activitypub.GetActorFromDB(config.Domain) + return actor.GetFollowingResp(ctx) } func Followers(ctx *fiber.Ctx) error { - // STUB - return activitypub.GetActorFollowers(ctx, config.Domain) + actor, _ := activitypub.GetActorFromDB(config.Domain) + return actor.GetFollowersResp(ctx) } diff --git a/routes/index.go b/routes/index.go index c088379..8f12664 100644 --- a/routes/index.go +++ b/routes/index.go @@ -16,7 +16,7 @@ func Index(ctx *fiber.Ctx) error { // this is a activitpub json request return json instead of html page if activitypub.AcceptActivity(ctx.Get("Accept")) { - activitypub.GetActorInfo(ctx, actor.Id) + actor.GetInfoResp(ctx) return nil } diff --git a/routes/outbox.go b/routes/outbox.go index 62d99c4..b2ffb42 100644 --- a/routes/outbox.go +++ b/routes/outbox.go @@ -19,7 +19,7 @@ func Outbox(ctx *fiber.Ctx) error { } if activitypub.AcceptActivity(ctx.Get("Accept")) { - activitypub.GetActorOutbox(ctx, actor) + actor.GetOutbox(ctx) return nil } @@ -31,7 +31,7 @@ func OutboxGet(ctx *fiber.Ctx) error { actor, _ := activitypub.GetActorByNameFromDB(ctx.Params("actor")) if activitypub.AcceptActivity(ctx.Get("Accept")) { - activitypub.GetActorInfo(ctx, actor.Id) + actor.GetInfoResp(ctx) return nil } diff --git a/routes/post.go b/routes/post.go index 7ed9e7d..1634346 100644 --- a/routes/post.go +++ b/routes/post.go @@ -31,8 +31,8 @@ func PostGet(ctx *fiber.Ctx) error { re := regexp.MustCompile("f(\\w|[!@#$%^&*<>])+-(\\w|[!@#$%^&*<>])+") - if re.MatchString(postId) { // if non local actor post - name := activitypub.GetActorFollowNameFromPath(postId) + if re.MatchString(ctx.Path()) { // if non local actor post + name := activitypub.GetActorFollowNameFromPath(ctx.Path()) followActors, err := webfinger.GetActorsFollowFromName(actor, name) if err != nil { diff --git a/routes/util.go b/routes/util.go index 8d36752..ee6d062 100644 --- a/routes/util.go +++ b/routes/util.go @@ -3,7 +3,10 @@ package routes import ( "errors" "fmt" + "html/template" + "regexp" "strings" + "time" "github.com/FChannel0/FChannel-Server/activitypub" "github.com/FChannel0/FChannel-Server/config" @@ -12,6 +15,7 @@ import ( "github.com/FChannel0/FChannel-Server/util" "github.com/FChannel0/FChannel-Server/webfinger" "github.com/gofiber/fiber/v2" + "github.com/gofiber/template/html" ) var ErrorPageLimit = errors.New("above page limit") @@ -85,7 +89,7 @@ func wantToServeArchive(actorName string) (activitypub.Collection, bool, error) } if actor.Id != "" { - collection, err = activitypub.GetActorCollectionDBType(actor.Id, "Archive") + collection, err = actor.GetCollectionType("Archive") if err != nil { return collection, false, err } @@ -222,7 +226,8 @@ func ParseOutboxRequest(ctx *fiber.Ctx, actor activitypub.Actor) error { } } - webfinger.FollowingBoards, err = activitypub.GetActorFollowingDB(config.Domain) + actor, _ := activitypub.GetActorFromDB(config.Domain) + webfinger.FollowingBoards, err = actor.GetFollowing() if err != nil { return err } @@ -298,3 +303,80 @@ func ParseOutboxRequest(ctx *fiber.Ctx, actor activitypub.Actor) error { return nil } + +func TemplateFunctions(engine *html.Engine) { + engine.AddFunc("mod", func(i, j int) bool { + return i%j == 0 + }) + + engine.AddFunc("sub", func(i, j int) int { + return i - j + }) + + engine.AddFunc("add", func(i, j int) int { + return i + j + }) + + engine.AddFunc("unixtoreadable", func(u int) string { + return time.Unix(int64(u), 0).Format("Jan 02, 2006") + }) + + engine.AddFunc("timeToReadableLong", func(t time.Time) string { + return t.Format("01/02/06(Mon)15:04:05") + }) + + engine.AddFunc("timeToUnix", func(t time.Time) string { + return fmt.Sprint(t.Unix()) + }) + + engine.AddFunc("proxy", util.MediaProxy) + + // previously short + engine.AddFunc("shortURL", util.ShortURL) + + engine.AddFunc("parseAttachment", post.ParseAttachment) + + engine.AddFunc("parseContent", post.ParseContent) + + engine.AddFunc("shortImg", util.ShortImg) + + engine.AddFunc("convertSize", util.ConvertSize) + + engine.AddFunc("isOnion", util.IsOnion) + + engine.AddFunc("parseReplyLink", func(actorId string, op string, id string, content string) template.HTML { + actor, _ := webfinger.FingerActor(actorId) + title := strings.ReplaceAll(post.ParseLinkTitle(actor.Id+"/", op, content), `/\<`, ">") + link := ">>" + util.ShortURL(actor.Outbox, id) + "" + return template.HTML(link) + }) + + engine.AddFunc("shortExcerpt", func(post activitypub.ObjectBase) string { + var returnString string + + if post.Name != "" { + returnString = post.Name + "| " + post.Content + } else { + returnString = post.Content + } + + re := regexp.MustCompile(`(^(.|\r\n|\n){100})`) + + match := re.FindStringSubmatch(returnString) + + if len(match) > 0 { + returnString = match[0] + "..." + } + + re = regexp.MustCompile(`(^.+\|)`) + + match = re.FindStringSubmatch(returnString) + + if len(match) > 0 { + returnString = strings.Replace(returnString, match[0], ""+match[0]+"", 1) + returnString = strings.Replace(returnString, "|", ":", 1) + } + + return returnString + }) +} diff --git a/util/util.go b/util/util.go index 0ffbf01..0126556 100644 --- a/util/util.go +++ b/util/util.go @@ -2,11 +2,14 @@ package util import ( "crypto/sha256" + "database/sql" "encoding/hex" "fmt" + "io/ioutil" "mime/multipart" "net/http" "os" + "path" "regexp" "strings" @@ -261,3 +264,41 @@ func CreatedNeededDirectories() { os.MkdirAll("./pem/board", 0700) } } + +func LoadThemes() { + // get list of themes + themes, err := ioutil.ReadDir("./static/css/themes") + if err != nil { + panic(err) + } + + for _, f := range themes { + if e := path.Ext(f.Name()); e == ".css" { + config.Themes = append(config.Themes, strings.TrimSuffix(f.Name(), e)) + } + } +} + +func GetBoardAuth(board string) ([]string, error) { + var auth []string + + query := `select type from actorauth where board=$1` + + var rows *sql.Rows + var err error + if rows, err = config.DB.Query(query, board); err != nil { + return auth, err + } + + defer rows.Close() + for rows.Next() { + var _type string + if err := rows.Scan(&_type); err != nil { + return auth, err + } + + auth = append(auth, _type) + } + + return auth, nil +} -- cgit v1.2.3