aboutsummaryrefslogtreecommitdiff
path: root/db
diff options
context:
space:
mode:
Diffstat (limited to 'db')
-rw-r--r--db/cache.go325
-rw-r--r--db/database.go47
-rw-r--r--db/follow.go481
-rw-r--r--db/pem.go313
-rw-r--r--db/verification.go342
5 files changed, 1172 insertions, 336 deletions
diff --git a/db/cache.go b/db/cache.go
new file mode 100644
index 0000000..0831f02
--- /dev/null
+++ b/db/cache.go
@@ -0,0 +1,325 @@
+package db
+
+import (
+ "fmt"
+
+ "github.com/FChannel0/FChannel-Server/activitypub"
+ "github.com/FChannel0/FChannel-Server/webfinger"
+ _ "github.com/lib/pq"
+)
+
+func WriteObjectToCache(obj activitypub.ObjectBase) (activitypub.ObjectBase, error) {
+ if res, err := IsPostBlacklist(obj.Content); err == nil && res {
+ fmt.Println("\n\nBlacklist post blocked\n\n")
+ return obj, nil
+ } else {
+ return obj, err
+ }
+
+ if len(obj.Attachment) > 0 {
+ if obj.Preview.Href != "" {
+ WritePreviewToCache(*obj.Preview)
+ }
+
+ for i, _ := range obj.Attachment {
+ WriteAttachmentToCache(obj.Attachment[i])
+ WriteActivitytoCacheWithAttachment(obj, obj.Attachment[i], *obj.Preview)
+ }
+
+ } else {
+ WriteActivitytoCache(obj)
+ }
+
+ WriteObjectReplyToDB(obj)
+
+ if obj.Replies != nil {
+ for _, e := range obj.Replies.OrderedItems {
+ WriteObjectToCache(e)
+ }
+ }
+
+ return obj, nil
+}
+
+func WriteActorObjectToCache(obj activitypub.ObjectBase) (activitypub.ObjectBase, error) {
+ if res, err := IsPostBlacklist(obj.Content); err == nil && res {
+ fmt.Println("\n\nBlacklist post blocked\n\n")
+ return obj, nil
+ } else if err != nil {
+ return obj, err
+ }
+
+ if len(obj.Attachment) > 0 {
+ if res, err := IsIDLocal(obj.Id); err == nil && res {
+ return obj, err
+ } else if err != nil {
+ return obj, err
+ }
+
+ if obj.Preview.Href != "" {
+ WritePreviewToCache(*obj.Preview)
+ }
+
+ for i, _ := range obj.Attachment {
+ WriteAttachmentToCache(obj.Attachment[i])
+ WriteActivitytoCacheWithAttachment(obj, obj.Attachment[i], *obj.Preview)
+ }
+
+ } else {
+ WriteActivitytoCache(obj)
+ }
+
+ WriteActorObjectReplyToDB(obj)
+
+ if obj.Replies != nil {
+ for _, e := range obj.Replies.OrderedItems {
+ WriteActorObjectToCache(e)
+ }
+ }
+
+ return obj, nil
+}
+
+func WriteActivitytoCache(obj activitypub.ObjectBase) error {
+ obj.Name = EscapeString(obj.Name)
+ obj.Content = EscapeString(obj.Content)
+ obj.AttributedTo = EscapeString(obj.AttributedTo)
+
+ query := `select id from cacheactivitystream where id=$1`
+
+ rows, err := db.Query(query, obj.Id)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ var id string
+ rows.Next()
+ err = rows.Scan(&id)
+ if err != nil {
+ return err
+ } else if id != "" {
+ return nil // TODO: error?
+ }
+
+ if obj.Updated.IsZero() {
+ obj.Updated = obj.Published
+ }
+
+ query = `insert into cacheactivitystream (id, type, name, content, published, updated, attributedto, actor, tripcode, sensitive) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`
+
+ _, err = db.Exec(query, obj.Id, obj.Type, obj.Name, obj.Content, obj.Published, obj.Updated, obj.AttributedTo, obj.Actor, obj.TripCode, obj.Sensitive)
+ return err
+}
+
+func WriteActivitytoCacheWithAttachment(obj activitypub.ObjectBase, attachment activitypub.ObjectBase, preview activitypub.NestedObjectBase) error {
+ obj.Name = EscapeString(obj.Name)
+ obj.Content = EscapeString(obj.Content)
+ obj.AttributedTo = EscapeString(obj.AttributedTo)
+
+ query := `select id from cacheactivitystream where id=$1`
+
+ rows, err := db.Query(query, obj.Id)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ var id string
+ rows.Next()
+ err = rows.Scan(&id)
+ if err != nil {
+ return err
+ } else if id != "" {
+ return nil // TODO: error?
+ }
+
+ if obj.Updated.IsZero() {
+ obj.Updated = obj.Published
+ }
+
+ query = `insert into cacheactivitystream (id, type, name, content, attachment, preview, published, updated, attributedto, actor, tripcode, sensitive) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`
+
+ _, err = db.Exec(query, obj.Id, obj.Type, obj.Name, obj.Content, attachment.Id, preview.Id, obj.Published, obj.Updated, obj.AttributedTo, obj.Actor, obj.TripCode, obj.Sensitive)
+ return err
+}
+
+func WriteAttachmentToCache(obj activitypub.ObjectBase) error {
+ query := `select id from cacheactivitystream where id=$1`
+
+ rows, err := db.Query(query, obj.Id)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ var id string
+ rows.Next()
+ err = rows.Scan(&id)
+ if err != nil {
+ return err
+ } else if id != "" {
+ return nil // TODO: error?
+ }
+
+ if obj.Updated.IsZero() {
+ obj.Updated = obj.Published
+ }
+
+ query = `insert into cacheactivitystream (id, type, name, href, published, updated, attributedTo, mediatype, size) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)`
+
+ _, err = db.Exec(query, obj.Id, obj.Type, obj.Name, obj.Href, obj.Published, obj.Updated, obj.AttributedTo, obj.MediaType, obj.Size)
+ return err
+}
+
+func WritePreviewToCache(obj activitypub.NestedObjectBase) error {
+ query := `select id from cacheactivitystream where id=$1`
+
+ rows, err := db.Query(query, obj.Id)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ var id string
+ rows.Next()
+ err = rows.Scan(&id)
+ if err != nil {
+ return err
+ } else if id != "" {
+ return nil // TODO: error?
+ }
+
+ if obj.Updated.IsZero() {
+ obj.Updated = obj.Published
+ }
+
+ query = `insert into cacheactivitystream (id, type, name, href, published, updated, attributedTo, mediatype, size) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)`
+
+ _, err = db.Exec(query, obj.Id, obj.Type, obj.Name, obj.Href, obj.Published, obj.Updated, obj.AttributedTo, obj.MediaType, obj.Size)
+ return err
+}
+
+func WriteObjectReplyToCache(obj activitypub.ObjectBase) error {
+ for i, e := range obj.InReplyTo {
+ res, err := IsReplyInThread(obj.InReplyTo[0].Id, e.Id)
+ if err != nil {
+ return err
+ }
+
+ if i == 0 || res {
+ query := `select id from replies where id=$1`
+
+ rows, err := db.Query(query, obj.Id)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ var id string
+ rows.Next()
+ err = rows.Scan(&id)
+ if err != nil {
+ return err
+ } else if id != "" {
+ return nil // TODO: error?
+ }
+
+ query = `insert into cachereplies (id, inreplyto) values ($1, $2)`
+
+ _, err = db.Exec(query, obj.Id, e.Id)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ if len(obj.InReplyTo) < 1 {
+ query := `insert into cachereplies (id, inreplyto) values ($1, $2)`
+
+ _, err := db.Exec(query, obj.Id, "")
+ return err
+ }
+
+ return nil
+}
+
+func WriteObjectReplyCache(obj activitypub.ObjectBase) error {
+ if obj.Replies != nil {
+ for _, e := range obj.Replies.OrderedItems {
+
+ query := `select inreplyto from cachereplies where id=$1`
+
+ rows, err := db.Query(query, obj.Id)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ var inreplyto string
+ rows.Next()
+ err = rows.Scan(&inreplyto)
+ if err != nil {
+ return err
+ } else if inreplyto != "" {
+ return nil // TODO: error?
+ }
+
+ query = `insert into cachereplies (id, inreplyto) values ($1, $2)`
+
+ if _, err := db.Exec(query, e.Id, obj.Id); err != nil {
+ return err
+ }
+
+ if res, err := IsObjectLocal(e.Id); err == nil && !res {
+ if _, err := WriteObjectToCache(e); err != nil {
+ return err
+ }
+ } else if err != nil {
+ return err
+ }
+
+ }
+ }
+
+ return nil
+}
+
+func WriteActorToCache(actorID string) error {
+ actor, err := webfinger.FingerActor(actorID)
+ if err != nil {
+ return err
+ }
+ collection := GetActorCollection(actor.Outbox)
+
+ for _, e := range collection.OrderedItems {
+ if _, err := WriteActorObjectToCache(e); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func DeleteActorCache(actorID string) error {
+ query := `select id from cacheactivitystream where id in (select id from cacheactivitystream where actor=$1)`
+
+ rows, err := db.Query(query, actorID)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var id string
+ if err := rows.Scan(&id); err != nil {
+ return err
+ }
+
+ if err := DeleteObject(id); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/db/database.go b/db/database.go
index b06bbf2..8bb7568 100644
--- a/db/database.go
+++ b/db/database.go
@@ -4,6 +4,7 @@ import (
"database/sql"
"fmt"
"html/template"
+ "io/ioutil"
"os"
"regexp"
"sort"
@@ -55,7 +56,7 @@ func Close() error {
return db.Close()
}
-func CreateUniqueID(db *sql.DB, actor string) (string, error) {
+func CreateUniqueID(actor string) (string, error) {
var newID string
isUnique := false
for !isUnique {
@@ -83,6 +84,16 @@ func CreateUniqueID(db *sql.DB, actor string) (string, error) {
return newID, nil
}
+func RunDatabaseSchema() error {
+ query, err := ioutil.ReadFile("databaseschema.psql")
+ if err != nil {
+ return err
+ }
+
+ _, err = db.Exec(string(query))
+ return err
+}
+
func GetActorFromDB(id string) (activitypub.Actor, error) {
var nActor activitypub.Actor
@@ -222,8 +233,12 @@ func CreateNewBoardDB(actor activitypub.Actor) (activitypub.Actor, error) {
nActivity.To = append(nActivity.To, actor.Id)
response := AcceptFollow(nActivity)
- SetActorFollowingDB(db, response)
- MakeActivityRequest(db, nActivity)
+ if _, err := SetActorFollowingDB(response); err != nil {
+ return actor, err
+ }
+ if err := MakeActivityRequest(nActivity); err != nil {
+ return actor, err
+ }
}
}
@@ -256,7 +271,7 @@ func GetBoards() ([]activitypub.Actor, error) {
}
func WriteObjectToDB(obj activitypub.ObjectBase) (activitypub.ObjectBase, error) {
- id, err := CreateUniqueID(db, obj.Actor)
+ id, err := CreateUniqueID(obj.Actor)
if err != nil {
return obj, err
}
@@ -264,7 +279,7 @@ func WriteObjectToDB(obj activitypub.ObjectBase) (activitypub.ObjectBase, error)
obj.Id = fmt.Sprintf("%s/%s", obj.Actor, id)
if len(obj.Attachment) > 0 {
if obj.Preview.Href != "" {
- id, err := CreateUniqueID(db, obj.Actor)
+ id, err := CreateUniqueID(obj.Actor)
if err != nil {
return obj, err
}
@@ -277,7 +292,7 @@ func WriteObjectToDB(obj activitypub.ObjectBase) (activitypub.ObjectBase, error)
}
for i, _ := range obj.Attachment {
- id, err := CreateUniqueID(db, obj.Actor)
+ id, err := CreateUniqueID(obj.Actor)
if err != nil {
return obj, err
}
@@ -1023,7 +1038,7 @@ func GetObjectRepliesDBLimit(parent activitypub.ObjectBase, limit int) (*activit
nColl.OrderedItems = result
- sort.Sort(ObjectBaseSortAsc(nColl.OrderedItems))
+ sort.Sort(activitypub.ObjectBaseSortAsc(nColl.OrderedItems))
return &nColl, postCount, attachCount, nil
}
@@ -2244,6 +2259,9 @@ func UpdateObjectTypeDB(id string, nType string) error {
func UnArchiveLast(actorId string) error {
col, err := GetActorCollectionDBTypeLimit(actorId, "Archive", 1)
+ if err != nil {
+ return err
+ }
for _, e := range col.OrderedItems {
for _, k := range e.Replies.OrderedItems {
@@ -2296,3 +2314,18 @@ func GetObjectTypeDB(id string) (string, error) {
return nType, nil
}
+
+func IsReplyInThread(inReplyTo string, id string) (bool, error) {
+ obj, _, err := CheckValidActivity(inReplyTo)
+ if err != nil {
+ return false, err
+ }
+
+ for _, e := range obj.OrderedItems[0].Replies.OrderedItems {
+ if e.Id == id {
+ return true, nil
+ }
+ }
+
+ return false, nil
+}
diff --git a/db/follow.go b/db/follow.go
new file mode 100644
index 0000000..386de2b
--- /dev/null
+++ b/db/follow.go
@@ -0,0 +1,481 @@
+package db
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/http"
+ "regexp"
+ "strings"
+ "time"
+
+ "github.com/FChannel0/FChannel-Server/activitypub"
+ "github.com/FChannel0/FChannel-Server/config"
+ "github.com/FChannel0/FChannel-Server/util"
+ "github.com/FChannel0/FChannel-Server/webfinger"
+ _ "github.com/lib/pq"
+)
+
+func GetActorFollowing(w http.ResponseWriter, id string) error {
+ var following activitypub.Collection
+ var err error
+
+ following.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+ following.Type = "Collection"
+ following.TotalItems, _, err = GetActorFollowTotal(id)
+ if err != nil {
+ return err
+ }
+
+ following.Items, err = GetActorFollowingDB(id)
+ if err != nil {
+ return err
+ }
+
+ enc, _ := json.MarshalIndent(following, "", "\t")
+ w.Header().Set("Content-Type", config.ActivityStreams)
+ _, err = w.Write(enc)
+
+ return err
+}
+
+func GetActorFollowers(w http.ResponseWriter, id string) error {
+ var following activitypub.Collection
+ var err error
+
+ following.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+ following.Type = "Collection"
+ _, following.TotalItems, err = GetActorFollowTotal(id)
+ if err != nil {
+ return err
+ }
+
+ following.Items, err = GetActorFollowDB(id)
+ if err != nil {
+ return err
+ }
+
+ enc, _ := json.MarshalIndent(following, "", "\t")
+ w.Header().Set("Content-Type", config.ActivityStreams)
+ _, err = w.Write(enc)
+ return err
+}
+
+func GetActorFollowingDB(id string) ([]activitypub.ObjectBase, error) {
+ var followingCollection []activitypub.ObjectBase
+ query := `select following from following where id=$1`
+
+ rows, err := db.Query(query, id)
+ if err != nil {
+ return followingCollection, err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var obj activitypub.ObjectBase
+
+ if err := rows.Scan(&obj.Id); err != nil {
+ return followingCollection, err
+ }
+
+ followingCollection = append(followingCollection, obj)
+ }
+
+ return followingCollection, nil
+}
+
+func GetActorFollowDB(id string) ([]activitypub.ObjectBase, error) {
+ var followerCollection []activitypub.ObjectBase
+
+ query := `select follower from follower where id=$1`
+
+ rows, err := db.Query(query, id)
+ if err != nil {
+ return followerCollection, err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var obj activitypub.ObjectBase
+
+ if err := rows.Scan(&obj.Id); err != nil {
+ return followerCollection, err
+ }
+
+ followerCollection = append(followerCollection, obj)
+ }
+
+ return followerCollection, nil
+}
+
+func GetActorFollowTotal(id string) (int, int, error) {
+ var following int
+ var followers int
+
+ query := `select count(following) from following where id=$1`
+
+ rows, err := 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
+ }
+ }
+
+ query = `select count(follower) from follower where id=$1`
+
+ rows, err = db.Query(query, id)
+ if err != nil {
+ return 0, 0, err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ if err := rows.Scan(&followers); err != nil {
+ return following, followers, err
+ }
+
+ }
+
+ return following, followers, nil
+}
+
+func AcceptFollow(activity activitypub.Activity) activitypub.Activity {
+ var accept activitypub.Activity
+ accept.AtContext.Context = activity.AtContext.Context
+ accept.Type = "Accept"
+ var nActor activitypub.Actor
+ accept.Actor = &nActor
+ accept.Actor.Id = activity.Object.Actor
+ var nObj activitypub.ObjectBase
+ accept.Object = &nObj
+ accept.Object.Actor = activity.Actor.Id
+ var nNested activitypub.NestedObjectBase
+ accept.Object.Object = &nNested
+ accept.Object.Object.Actor = activity.Object.Actor
+ accept.Object.Object.Type = "Follow"
+ accept.To = append(accept.To, activity.Object.Actor)
+
+ return accept
+}
+
+func RejectActivity(activity activitypub.Activity) activitypub.Activity {
+ var accept activitypub.Activity
+ accept.AtContext.Context = activity.AtContext.Context
+ accept.Type = "Reject"
+ var nObj activitypub.ObjectBase
+ accept.Object = &nObj
+ var nActor activitypub.Actor
+ accept.Actor = &nActor
+ accept.Actor.Id = activity.Object.Actor
+ accept.Object.Actor = activity.Actor.Id
+ var nNested activitypub.NestedObjectBase
+ accept.Object.Object = &nNested
+ accept.Object.Object.Actor = activity.Object.Actor
+ accept.Object.Object.Type = "Follow"
+ accept.To = append(accept.To, activity.Actor.Id)
+
+ return accept
+}
+
+func IsAlreadyFollowing(actor string, follow string) (bool, error) {
+ followers, err := GetActorFollowingDB(actor)
+ if err != nil {
+ return false, err
+ }
+
+ for _, e := range followers {
+ if e.Id == follow {
+ return true, nil
+ }
+ }
+
+ return false, nil
+}
+
+func IsAlreadyFollower(actor string, follow string) (bool, error) {
+ followers, err := GetActorFollowDB(actor)
+ if err != nil {
+ return false, err
+ }
+
+ for _, e := range followers {
+ if e.Id == follow {
+ return true, nil
+ }
+ }
+
+ return false, nil
+}
+
+func SetActorFollowerDB(activity activitypub.Activity) (activitypub.Activity, error) {
+ var query string
+ alreadyFollow, err := IsAlreadyFollower(activity.Actor.Id, activity.Object.Actor)
+ if err != nil {
+ return activity, err
+ }
+
+ activity.Type = "Reject"
+ if activity.Actor.Id == activity.Object.Actor {
+ return activity, nil
+ }
+
+ if alreadyFollow {
+ query = `delete from follower where id=$1 and follower=$2`
+ activity.Summary = activity.Object.Actor + " Unfollow " + activity.Actor.Id
+
+ if _, err := db.Exec(query, activity.Actor.Id, activity.Object.Actor); err != nil {
+ return activity, err
+ }
+
+ activity.Type = "Accept"
+ return activity, err
+ }
+
+ query = `insert into follower (id, follower) values ($1, $2)`
+ activity.Summary = activity.Object.Actor + " Follow " + activity.Actor.Id
+
+ if _, err := db.Exec(query, activity.Actor.Id, activity.Object.Actor); err != nil {
+ return activity, err
+ }
+
+ activity.Type = "Accept"
+ return activity, nil
+}
+
+func SetActorFollowingDB(activity activitypub.Activity) (activitypub.Activity, error) {
+ var query string
+ alreadyFollowing := false
+ alreadyFollower := false
+ following, err := GetActorFollowingDB(activity.Object.Actor)
+ if err != nil {
+ return activity, err
+ }
+
+ actor, err := webfinger.FingerActor(activity.Actor.Id)
+ if err != nil {
+ return activity, err
+ }
+
+ remoteActorFollowerCol := GetCollectionFromReq(actor.Followers)
+
+ for _, e := range following {
+ if e.Id == activity.Actor.Id {
+ alreadyFollowing = true
+ }
+ }
+
+ for _, e := range remoteActorFollowerCol.Items {
+ if e.Id == activity.Object.Actor {
+ alreadyFollower = true
+ }
+ }
+
+ activity.Type = "Reject"
+
+ if activity.Actor.Id == activity.Object.Actor {
+ return activity, nil
+ }
+
+ if alreadyFollowing && alreadyFollower {
+ query = `delete from following where id=$1 and following=$2`
+ activity.Summary = activity.Object.Actor + " Unfollowing " + activity.Actor.Id
+ if res, err := IsActorLocal(activity.Actor.Id); err == nil && !res {
+ go DeleteActorCache(activity.Actor.Id)
+ } else {
+ return activity, err
+ }
+
+ if _, err := db.Exec(query, activity.Object.Actor, activity.Actor.Id); err != nil {
+ return activity, err
+ }
+
+ activity.Type = "Accept"
+ return activity, nil
+ }
+
+ if !alreadyFollowing && !alreadyFollower {
+
+ query = `insert into following (id, following) values ($1, $2)`
+ activity.Summary = activity.Object.Actor + " Following " + activity.Actor.Id
+ if res, err := IsActorLocal(activity.Actor.Id); err == nil && !res {
+ go WriteActorToCache(activity.Actor.Id)
+ }
+ if _, err := db.Exec(query, activity.Object.Actor, activity.Actor.Id); err != nil {
+ return activity, err
+ }
+
+ activity.Type = "Accept"
+ return activity, nil
+ }
+
+ return activity, nil
+}
+
+func AutoFollow(actor string) error {
+ following, err := GetActorFollowingDB(actor)
+ if err != nil {
+ return err
+ }
+
+ follower, err := GetActorFollowDB(actor)
+ if err != nil {
+ return err
+ }
+
+ isFollowing := false
+
+ for _, e := range follower {
+ for _, k := range following {
+ if e.Id == k.Id {
+ isFollowing = true
+ }
+ }
+
+ if !isFollowing && e.Id != config.Domain && e.Id != actor {
+ followActivity, err := MakeFollowActivity(actor, e.Id)
+ if err != nil {
+ return err
+ }
+
+ nActor, err := webfinger.FingerActor(e.Id)
+ if err != nil {
+ return err
+ }
+
+ if nActor.Id != "" {
+ MakeActivityRequestOutbox(followActivity)
+ }
+ }
+ }
+
+ return nil
+}
+
+func MakeFollowActivity(actor string, follow string) (activitypub.Activity, error) {
+ var followActivity activitypub.Activity
+ var err error
+
+ followActivity.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+ followActivity.Type = "Follow"
+
+ var obj activitypub.ObjectBase
+ var nactor activitypub.Actor
+ if actor == config.Domain {
+ nactor, err = GetActorFromDB(actor)
+ } else {
+ nactor, err = webfinger.FingerActor(actor)
+ }
+
+ if err != nil {
+ return followActivity, err
+ }
+
+ followActivity.Actor = &nactor
+ followActivity.Object = &obj
+
+ followActivity.Object.Actor = follow
+ followActivity.To = append(followActivity.To, follow)
+
+ return followActivity, nil
+}
+
+func MakeActivityRequestOutbox(activity activitypub.Activity) error {
+ j, _ := json.Marshal(activity)
+
+ if activity.Actor.Outbox == "" {
+ // TODO: good enough?
+ return errors.New("invalid outbox")
+ }
+
+ req, err := http.NewRequest("POST", activity.Actor.Outbox, bytes.NewBuffer(j))
+ if err != nil {
+ return err
+ }
+
+ re := regexp.MustCompile("https?://(www.)?")
+
+ var instance string
+ if activity.Actor.Id == config.Domain {
+ instance = re.ReplaceAllString(config.Domain, "")
+ } else {
+ _, instance = util.GetActorInstance(activity.Actor.Id)
+ }
+
+ date := time.Now().UTC().Format(time.RFC1123)
+ path := strings.Replace(activity.Actor.Outbox, instance, "", 1)
+
+ path = re.ReplaceAllString(path, "")
+
+ sig := fmt.Sprintf("(request-target): %s %s\nhost: %s\ndate: %s", "post", path, instance, date)
+ encSig, err := ActivitySign(*activity.Actor, sig)
+ if err != nil {
+ return err
+ }
+
+ signature := fmt.Sprintf("keyId=\"%s\",headers=\"(request-target) host date\",signature=\"%s\"", activity.Actor.PublicKey.Id, encSig)
+
+ req.Header.Set("Content-Type", config.ActivityStreams)
+ req.Header.Set("Date", date)
+ req.Header.Set("Signature", signature)
+ req.Host = instance
+
+ _, err = util.RouteProxy(req)
+ return err
+}
+
+func MakeActivityRequest(activity activitypub.Activity) error {
+ j, _ := json.MarshalIndent(activity, "", "\t")
+
+ for _, e := range activity.To {
+ if e != activity.Actor.Id {
+ actor, err := webfinger.FingerActor(e)
+ if err != nil {
+ return err
+ }
+
+ if actor.Id != "" {
+ _, instance := util.GetActorInstance(actor.Id)
+
+ if actor.Inbox != "" {
+ req, err := http.NewRequest("POST", actor.Inbox, bytes.NewBuffer(j))
+ if err != nil {
+ return err
+ }
+
+ date := time.Now().UTC().Format(time.RFC1123)
+ path := strings.Replace(actor.Inbox, instance, "", 1)
+
+ re := regexp.MustCompile("https?://(www.)?")
+ path = re.ReplaceAllString(path, "")
+
+ sig := fmt.Sprintf("(request-target): %s %s\nhost: %s\ndate: %s", "post", path, instance, date)
+ encSig, err := ActivitySign(*activity.Actor, sig)
+ if err != nil {
+ return err
+ }
+
+ signature := fmt.Sprintf("keyId=\"%s\",headers=\"(request-target) host date\",signature=\"%s\"", activity.Actor.PublicKey.Id, encSig)
+
+ req.Header.Set("Content-Type", config.ActivityStreams)
+ req.Header.Set("Date", date)
+ req.Header.Set("Signature", signature)
+ req.Host = instance
+
+ _, err = util.RouteProxy(req)
+ if err != nil {
+ fmt.Println("error with sending activity resp to actor " + instance)
+ return err // TODO: needs further testing
+ }
+ }
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/db/pem.go b/db/pem.go
index d9bcee2..dedb137 100644
--- a/db/pem.go
+++ b/db/pem.go
@@ -1,10 +1,24 @@
package db
import (
+ "crypto"
+ crand "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha256"
+ "crypto/x509"
+ "encoding/base64"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "net/http"
"os"
+ "regexp"
"strings"
+ "time"
"github.com/FChannel0/FChannel-Server/activitypub"
+ "github.com/FChannel0/FChannel-Server/webfinger"
)
func GetActorPemFromDB(pemID string) (activitypub.PublicKeyPem, error) {
@@ -46,3 +60,302 @@ func GetActorPemFileFromDB(pemID string) (string, error) {
return file, nil
}
+
+func CreatePem(actor activitypub.Actor) error {
+ privatekey, err := rsa.GenerateKey(crand.Reader, 2048)
+ if err != nil {
+ return err
+ }
+
+ privateKeyBytes := x509.MarshalPKCS1PrivateKey(privatekey)
+
+ privateKeyBlock := &pem.Block{
+ Type: "RSA PRIVATE KEY",
+ Bytes: privateKeyBytes,
+ }
+
+ privatePem, err := os.Create("./pem/board/" + actor.Name + "-private.pem")
+ if err != nil {
+ return err
+ }
+
+ if err := pem.Encode(privatePem, privateKeyBlock); err != nil {
+ return err
+ }
+
+ publickey := &privatekey.PublicKey
+ publicKeyBytes, err := x509.MarshalPKIXPublicKey(publickey)
+ if err != nil {
+ return err
+ }
+
+ publicKeyBlock := &pem.Block{
+ Type: "PUBLIC KEY",
+ Bytes: publicKeyBytes,
+ }
+
+ publicPem, err := os.Create("./pem/board/" + actor.Name + "-public.pem")
+ if err != nil {
+ return err
+ }
+
+ if err := pem.Encode(publicPem, publicKeyBlock); err != nil {
+ return err
+ }
+
+ _, err = os.Stat("./pem/board/" + actor.Name + "-public.pem")
+ if os.IsNotExist(err) {
+ return err
+ } else {
+ return StorePemToDB(actor)
+ }
+
+ fmt.Println(`Created PEM keypair for the "` + actor.Name + `" board. Please keep in mind that
+the PEM key is crucial in identifying yourself as the legitimate owner of the board,
+so DO NOT LOSE IT!!! If you lose it, YOU WILL LOSE ACCESS TO YOUR BOARD!`)
+
+ return nil
+}
+
+func CreatePublicKeyFromPrivate(actor *activitypub.Actor, publicKeyPem string) error {
+ publicFilename, err := GetActorPemFileFromDB(publicKeyPem)
+ if err != nil {
+ return err
+ }
+
+ privateFilename := strings.ReplaceAll(publicFilename, "public.pem", "private.pem")
+ if _, err := os.Stat(privateFilename); err == nil {
+ // Not a lost cause
+ priv, err := ioutil.ReadFile(privateFilename)
+ if err != nil {
+ return err
+ }
+
+ block, _ := pem.Decode([]byte(priv))
+ if block == nil || block.Type != "RSA PRIVATE KEY" {
+ return errors.New("failed to decode PEM block containing public key")
+ }
+
+ key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ return err
+ }
+
+ publicKeyDer, err := x509.MarshalPKIXPublicKey(&key.PublicKey)
+ if err != nil {
+ return err
+ }
+
+ pubKeyBlock := pem.Block{
+ Type: "PUBLIC KEY",
+ Headers: nil,
+ Bytes: publicKeyDer,
+ }
+
+ publicFileWriter, err := os.Create(publicFilename)
+ if err != nil {
+ return err
+ }
+
+ if err := pem.Encode(publicFileWriter, &pubKeyBlock); err != nil {
+ return err
+ }
+ } else {
+ fmt.Println(`\nUnable to locate private key from public key generation. Now,
+this means that you are now missing the proof that you are the
+owner of the "` + actor.Name + `" board. If you are the developer,
+then your job is just as easy as generating a new keypair, but
+if this board is live, then you'll also have to convince the other
+owners to switch their public keys for you so that they will start
+accepting your posts from your board from this site. Good luck ;)`)
+ return errors.New("unable to locate private key")
+ }
+ return nil
+}
+
+func StorePemToDB(actor activitypub.Actor) error {
+ query := "select publicKeyPem from actor where id=$1"
+ rows, err := db.Query(query, actor.Id)
+ if err != nil {
+ return err
+ }
+
+ defer rows.Close()
+
+ var result string
+ rows.Next()
+ rows.Scan(&result)
+
+ if result != "" {
+ return errors.New("already storing public key for actor")
+ }
+
+ publicKeyPem := actor.Id + "#main-key"
+ query = "update actor set publicKeyPem=$1 where id=$2"
+ if _, err := db.Exec(query, publicKeyPem, actor.Id); err != nil {
+ return err
+ }
+
+ file := "./pem/board/" + actor.Name + "-public.pem"
+ query = "insert into publicKeyPem (id, owner, file) values($1, $2, $3)"
+ _, err = db.Exec(query, publicKeyPem, actor.Id, file)
+ return err
+}
+func ActivitySign(actor activitypub.Actor, signature string) (string, error) {
+ query := `select file from publicKeyPem where id=$1 `
+
+ rows, err := db.Query(query, actor.PublicKey.Id)
+ if err != nil {
+ return "", err
+ }
+
+ defer rows.Close()
+
+ var file string
+ rows.Next()
+ rows.Scan(&file)
+
+ file = strings.ReplaceAll(file, "public.pem", "private.pem")
+ _, err = os.Stat(file)
+ if err != nil {
+ fmt.Println(`\n Unable to locate private key. Now,
+this means that you are now missing the proof that you are the
+owner of the "` + actor.Name + `" board. If you are the developer,
+then your job is just as easy as generating a new keypair, but
+if this board is live, then you'll also have to convince the other
+owners to switch their public keys for you so that they will start
+accepting your posts from your board from this site. Good luck ;)`)
+ return "", errors.New("unable to locate private key")
+ }
+
+ publickey, err := ioutil.ReadFile(file)
+ if err != nil {
+ return "", err
+ }
+
+ block, _ := pem.Decode(publickey)
+
+ pub, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
+ rng := crand.Reader
+ hashed := sha256.New()
+ hashed.Write([]byte(signature))
+ cipher, _ := rsa.SignPKCS1v15(rng, pub, crypto.SHA256, hashed.Sum(nil))
+
+ return base64.StdEncoding.EncodeToString(cipher), nil
+}
+
+func ActivityVerify(actor activitypub.Actor, signature string, verify string) error {
+ sig, _ := base64.StdEncoding.DecodeString(signature)
+
+ if actor.PublicKey.PublicKeyPem == "" {
+ _actor, err := webfinger.FingerActor(actor.Id)
+ if err != nil {
+ return err
+ }
+ actor = _actor
+ }
+
+ block, _ := pem.Decode([]byte(actor.PublicKey.PublicKeyPem))
+ pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
+
+ hashed := sha256.New()
+ hashed.Write([]byte(verify))
+
+ return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hashed.Sum(nil), sig)
+}
+
+func VerifyHeaderSignature(r *http.Request, actor activitypub.Actor) bool {
+ s := ParseHeaderSignature(r.Header.Get("Signature"))
+
+ var method string
+ var path string
+ var host string
+ var date string
+ var digest string
+ var contentLength string
+
+ var sig string
+ for i, e := range s.Headers {
+ var nl string
+ if i < len(s.Headers)-1 {
+ nl = "\n"
+ }
+
+ switch e {
+ case "(request-target)":
+ method = strings.ToLower(r.Method)
+ path = r.URL.Path
+ sig += "(request-target): " + method + " " + path + "" + nl
+ break
+ case "host":
+ host = r.Host
+ sig += "host: " + host + "" + nl
+ break
+ case "date":
+ date = r.Header.Get("date")
+ sig += "date: " + date + "" + nl
+ break
+ case "digest":
+ digest = r.Header.Get("digest")
+ sig += "digest: " + digest + "" + nl
+ break
+ case "content-length":
+ contentLength = r.Header.Get("content-length")
+ sig += "content-length: " + contentLength + "" + nl
+ break
+ }
+ }
+
+ if s.KeyId != actor.PublicKey.Id {
+ return false
+ }
+
+ t, _ := time.Parse(time.RFC1123, date)
+
+ if time.Now().UTC().Sub(t).Seconds() > 75 {
+ return false
+ }
+
+ if ActivityVerify(actor, s.Signature, sig) != nil {
+ return false
+ }
+
+ return true
+}
+
+func ParseHeaderSignature(signature string) Signature {
+ var nsig Signature
+
+ keyId := regexp.MustCompile(`keyId=`)
+ headers := regexp.MustCompile(`headers=`)
+ sig := regexp.MustCompile(`signature=`)
+ algo := regexp.MustCompile(`algorithm=`)
+
+ signature = strings.ReplaceAll(signature, "\"", "")
+ parts := strings.Split(signature, ",")
+
+ for _, e := range parts {
+ if keyId.MatchString(e) {
+ nsig.KeyId = keyId.ReplaceAllString(e, "")
+ continue
+ }
+
+ if headers.MatchString(e) {
+ header := headers.ReplaceAllString(e, "")
+ nsig.Headers = strings.Split(header, " ")
+ continue
+ }
+
+ if sig.MatchString(e) {
+ nsig.Signature = sig.ReplaceAllString(e, "")
+ continue
+ }
+
+ if algo.MatchString(e) {
+ nsig.Algorithm = algo.ReplaceAllString(e, "")
+ continue
+ }
+ }
+
+ return nsig
+}
diff --git a/db/verification.go b/db/verification.go
index b976908..8be2ffe 100644
--- a/db/verification.go
+++ b/db/verification.go
@@ -1,13 +1,6 @@
package db
import (
- "crypto"
- "crypto/rsa"
- "crypto/sha256"
- "crypto/x509"
- "encoding/base64"
- "encoding/pem"
- "errors"
"fmt"
"math/rand"
"net/smtp"
@@ -15,14 +8,9 @@ import (
"os/exec"
"time"
- "github.com/FChannel0/FChannel-Server/activitypub"
+ "github.com/FChannel0/FChannel-Server/config"
+ "github.com/FChannel0/FChannel-Server/util"
_ "github.com/lib/pq"
-
- crand "crypto/rand"
- "io/ioutil"
- "net/http"
- "regexp"
- "strings"
)
type Verify struct {
@@ -97,7 +85,7 @@ func GetBoardMod(identifier string) (Verify, error) {
}
func CreateBoardMod(verify Verify) error {
- pass := CreateKey(50)
+ pass := util.CreateKey(50)
query := `select code from verification where identifier=$1 and type=$2`
@@ -307,8 +295,8 @@ func VerficationCooldownRemove() error {
func SendVerification(verify Verify) error {
fmt.Println("sending email")
- from := SiteEmail
- pass := SiteEmailPassword
+ from := config.SiteEmail
+ pass := config.SiteEmailPassword
to := verify.Identifier
body := fmt.Sprintf("You can use either\r\nEmail: %s \r\n Verfication Code: %s\r\n for the board %s", verify.Identifier, verify.Code, verify.Board)
@@ -317,23 +305,13 @@ func SendVerification(verify Verify) error {
"Subject: Image Board Verification\n\n" +
body
- return smtp.SendMail(SiteEmailServer+":"+SiteEmailPort,
- smtp.PlainAuth("", from, pass, SiteEmailServer),
+ return smtp.SendMail(config.SiteEmailServer+":"+config.SiteEmailPort,
+ smtp.PlainAuth("", from, pass, config.SiteEmailServer),
from, []string{to}, []byte(msg))
}
func IsEmailSetup() bool {
- if SiteEmail == "" {
- return false
- } else if SiteEmailPassword == "" {
- return false
- } else if SiteEmailServer == "" {
- return false
- } else if SiteEmailPort == "" {
- return false
- }
-
- return true
+ return config.SiteEmail != "" || config.SiteEmailPassword != "" || config.SiteEmailServer != "" || config.SiteEmailPort != ""
}
func HasAuth(code string, board string) (bool, error) {
@@ -342,8 +320,10 @@ func HasAuth(code string, board string) (bool, error) {
return false, err
}
- if verify.Board == Domain || (HasBoardAccess(db, verify) && verify.Board == board) {
+ if res, err := HasBoardAccess(verify); err != nil && (verify.Board == config.Domain || (res && verify.Board == board)) {
return true, nil
+ } else {
+ return false, err
}
return false, nil
@@ -377,12 +357,12 @@ func GetVerify(access string) (Verify, error) {
}
func CreateNewCaptcha() error {
- id := RandomID(8)
+ id := util.RandomID(8)
file := "public/" + id + ".png"
for true {
if _, err := os.Stat("./" + file); err == nil {
- id = RandomID(8)
+ id = util.RandomID(8)
file = "public/" + id + ".png"
} else {
break
@@ -506,299 +486,3 @@ func Captcha() string {
return newID
}
-
-func CreatePem(actor Actor) error {
- privatekey, err := rsa.GenerateKey(crand.Reader, 2048)
- if err != nil {
- return err
- }
-
- privateKeyBytes := x509.MarshalPKCS1PrivateKey(privatekey)
-
- privateKeyBlock := &pem.Block{
- Type: "RSA PRIVATE KEY",
- Bytes: privateKeyBytes,
- }
-
- privatePem, err := os.Create("./pem/board/" + actor.Name + "-private.pem")
- if err != nil {
- return err
- }
-
- if err := pem.Encode(privatePem, privateKeyBlock); err != nil {
- return err
- }
-
- publickey := &privatekey.PublicKey
- publicKeyBytes, err := x509.MarshalPKIXPublicKey(publickey)
- if err != nil {
- return err
- }
-
- publicKeyBlock := &pem.Block{
- Type: "PUBLIC KEY",
- Bytes: publicKeyBytes,
- }
-
- publicPem, err := os.Create("./pem/board/" + actor.Name + "-public.pem")
- if err != nil {
- return err
- }
-
- if err := pem.Encode(publicPem, publicKeyBlock); err != nil {
- return err
- }
-
- _, err = os.Stat("./pem/board/" + actor.Name + "-public.pem")
- if os.IsNotExist(err) {
- return err
- } else {
- return StorePemToDB(actor)
- }
-
- fmt.Println(`Created PEM keypair for the "` + actor.Name + `" board. Please keep in mind that
-the PEM key is crucial in identifying yourself as the legitimate owner of the board,
-so DO NOT LOSE IT!!! If you lose it, YOU WILL LOSE ACCESS TO YOUR BOARD!`)
-
- return nil
-}
-
-func CreatePublicKeyFromPrivate(actor *activitypub.Actor, publicKeyPem string) error {
- publicFilename, err := GetActorPemFileFromDB(publicKeyPem)
- if err != nil {
- return err
- }
-
- privateFilename := strings.ReplaceAll(publicFilename, "public.pem", "private.pem")
- if _, err := os.Stat(privateFilename); err == nil {
- // Not a lost cause
- priv, err := ioutil.ReadFile(privateFilename)
- if err != nil {
- return err
- }
-
- block, _ := pem.Decode([]byte(priv))
- if block == nil || block.Type != "RSA PRIVATE KEY" {
- return errors.New("failed to decode PEM block containing public key")
- }
-
- key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
- if err != nil {
- return err
- }
-
- publicKeyDer, err := x509.MarshalPKIXPublicKey(&key.PublicKey)
- if err != nil {
- return err
- }
-
- pubKeyBlock := pem.Block{
- Type: "PUBLIC KEY",
- Headers: nil,
- Bytes: publicKeyDer,
- }
-
- publicFileWriter, err := os.Create(publicFilename)
- if err != nil {
- return err
- }
-
- if err := pem.Encode(publicFileWriter, &pubKeyBlock); err != nil {
- return err
- }
- } else {
- fmt.Println(`\nUnable to locate private key from public key generation. Now,
-this means that you are now missing the proof that you are the
-owner of the "` + actor.Name + `" board. If you are the developer,
-then your job is just as easy as generating a new keypair, but
-if this board is live, then you'll also have to convince the other
-owners to switch their public keys for you so that they will start
-accepting your posts from your board from this site. Good luck ;)`)
- return errors.New("unable to locate private key")
- }
- return nil
-}
-
-func StorePemToDB(actor activitypub.Actor) error {
- query := "select publicKeyPem from actor where id=$1"
- rows, err := db.Query(query, actor.Id)
- if err != nil {
- return err
- }
-
- defer rows.Close()
-
- var result string
- rows.Next()
- rows.Scan(&result)
-
- if result != "" {
- return errors.New("already storing public key for actor")
- }
-
- publicKeyPem := actor.Id + "#main-key"
- query = "update actor set publicKeyPem=$1 where id=$2"
- if _, err := db.Exec(query, publicKeyPem, actor.Id); err != nil {
- return err
- }
-
- file := "./pem/board/" + actor.Name + "-public.pem"
- query = "insert into publicKeyPem (id, owner, file) values($1, $2, $3)"
- _, err = db.Exec(query, publicKeyPem, actor.Id, file)
- return err
-}
-
-func ActivitySign(actor activitypub.Actor, signature string) (string, error) {
- query := `select file from publicKeyPem where id=$1 `
-
- rows, err := db.Query(query, actor.PublicKey.Id)
- if err != nil {
- return "", err
- }
-
- defer rows.Close()
-
- var file string
- rows.Next()
- rows.Scan(&file)
-
- file = strings.ReplaceAll(file, "public.pem", "private.pem")
- _, err = os.Stat(file)
- if err != nil {
- fmt.Println(`\n Unable to locate private key. Now,
-this means that you are now missing the proof that you are the
-owner of the "` + actor.Name + `" board. If you are the developer,
-then your job is just as easy as generating a new keypair, but
-if this board is live, then you'll also have to convince the other
-owners to switch their public keys for you so that they will start
-accepting your posts from your board from this site. Good luck ;)`)
- return "", errors.New("unable to locate private key")
- }
-
- publickey, err := ioutil.ReadFile(file)
- if err != nil {
- return "", err
- }
-
- block, _ := pem.Decode(publickey)
-
- pub, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
- rng := crand.Reader
- hashed := sha256.New()
- hashed.Write([]byte(signature))
- cipher, _ := rsa.SignPKCS1v15(rng, pub, crypto.SHA256, hashed.Sum(nil))
-
- return base64.StdEncoding.EncodeToString(cipher), nil
-}
-
-func ActivityVerify(actor activitypub.Actor, signature string, verify string) error {
- sig, _ := base64.StdEncoding.DecodeString(signature)
-
- if actor.PublicKey.PublicKeyPem == "" {
- actor = FingerActor(actor.Id)
- }
-
- block, _ := pem.Decode([]byte(actor.PublicKey.PublicKeyPem))
- pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
-
- hashed := sha256.New()
- hashed.Write([]byte(verify))
-
- return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hashed.Sum(nil), sig)
-}
-
-func VerifyHeaderSignature(r *http.Request, actor activitypub.Actor) bool {
- s := ParseHeaderSignature(r.Header.Get("Signature"))
-
- var method string
- var path string
- var host string
- var date string
- var digest string
- var contentLength string
-
- var sig string
- for i, e := range s.Headers {
- var nl string
- if i < len(s.Headers)-1 {
- nl = "\n"
- }
-
- switch e {
- case "(request-target)":
- method = strings.ToLower(r.Method)
- path = r.URL.Path
- sig += "(request-target): " + method + " " + path + "" + nl
- break
- case "host":
- host = r.Host
- sig += "host: " + host + "" + nl
- break
- case "date":
- date = r.Header.Get("date")
- sig += "date: " + date + "" + nl
- break
- case "digest":
- digest = r.Header.Get("digest")
- sig += "digest: " + digest + "" + nl
- break
- case "content-length":
- contentLength = r.Header.Get("content-length")
- sig += "content-length: " + contentLength + "" + nl
- break
- }
- }
-
- if s.KeyId != actor.PublicKey.Id {
- return false
- }
-
- t, _ := time.Parse(time.RFC1123, date)
-
- if time.Now().UTC().Sub(t).Seconds() > 75 {
- return false
- }
-
- if ActivityVerify(actor, s.Signature, sig) != nil {
- return false
- }
-
- return true
-}
-
-func ParseHeaderSignature(signature string) Signature {
- var nsig Signature
-
- keyId := regexp.MustCompile(`keyId=`)
- headers := regexp.MustCompile(`headers=`)
- sig := regexp.MustCompile(`signature=`)
- algo := regexp.MustCompile(`algorithm=`)
-
- signature = strings.ReplaceAll(signature, "\"", "")
- parts := strings.Split(signature, ",")
-
- for _, e := range parts {
- if keyId.MatchString(e) {
- nsig.KeyId = keyId.ReplaceAllString(e, "")
- continue
- }
-
- if headers.MatchString(e) {
- header := headers.ReplaceAllString(e, "")
- nsig.Headers = strings.Split(header, " ")
- continue
- }
-
- if sig.MatchString(e) {
- nsig.Signature = sig.ReplaceAllString(e, "")
- continue
- }
-
- if algo.MatchString(e) {
- nsig.Algorithm = algo.ReplaceAllString(e, "")
- continue
- }
- }
-
- return nsig
-}