aboutsummaryrefslogtreecommitdiff
path: root/OutboxPost.go
diff options
context:
space:
mode:
authorFChannel <=>2021-01-13 17:09:43 -0800
committerFChannel <=>2021-01-13 17:09:43 -0800
commit8fb8ccafa3452d4987098ccef5c1c0bf247db555 (patch)
tree0d3acb0b988e4f1f3f97abdb9af3c464da769a55 /OutboxPost.go
parent2aa578319c4e01425509597772160ef403aefbfc (diff)
initial commit
Diffstat (limited to 'OutboxPost.go')
-rw-r--r--OutboxPost.go545
1 files changed, 545 insertions, 0 deletions
diff --git a/OutboxPost.go b/OutboxPost.go
new file mode 100644
index 0000000..89173f9
--- /dev/null
+++ b/OutboxPost.go
@@ -0,0 +1,545 @@
+package main
+
+import "fmt"
+import "net/http"
+import "database/sql"
+import _ "github.com/lib/pq"
+import "encoding/json"
+import "reflect"
+import "io/ioutil"
+import "os"
+import "regexp"
+import "strings"
+
+func ParseOutboxRequest(w http.ResponseWriter, r *http.Request, db *sql.DB) {
+
+ var activity Activity
+ var object ObjectBase
+
+ actor := GetActorFromPath(db, r.URL.Path, "/")
+ contentType := GetContentType(r.Header.Get("content-type"))
+
+ defer r.Body.Close()
+ if contentType == "multipart/form-data" || contentType == "application/x-www-form-urlencoded" {
+ r.ParseMultipartForm(5 << 20)
+ if(BoardHasAuthType(db, actor.Name, "captcha") && CheckCaptcha(db, r.FormValue("captcha"))) {
+ f, header, _ := r.FormFile("file")
+ if(header != nil) {
+ if(header.Size > (5 << 20)){
+ w.WriteHeader(http.StatusRequestEntityTooLarge)
+ w.Write([]byte("5MB max file size"))
+ return
+ }
+
+ contentType, _ := GetFileContentType(f)
+
+ if(!SupportedMIMEType(contentType)) {
+ w.WriteHeader(http.StatusNotAcceptable)
+ w.Write([]byte("file type not supported"))
+ return
+ }
+
+ }
+
+ var nObj = CreateObject("Note")
+ nObj = ObjectFromForm(r, db, nObj)
+
+ var act Actor
+ nObj.Actor = &act
+ nObj.Actor.Id = Domain + "/" + actor.Name
+
+ delete := regexp.MustCompile("delete:.+")
+ for _, e := range nObj.Option {
+ if delete.MatchString(e) {
+ verification := strings.Replace(e, "delete:", "", 1)
+ if HasAuth(db, verification, Domain + "/" + actor.Name) {
+ for _, e := range nObj.InReplyTo {
+ if IsObjectLocal(db, e.Id) && e.Id != nObj.InReplyTo[len(nObj.InReplyTo) - 1].Id {
+ DeleteObject(db, e.Id)
+ nObj.Type = "Delete"
+ }
+ }
+ }
+ }
+ }
+
+ if nObj.Type != "Delete" {
+ nObj = writeObjectToDB(db, nObj)
+ activity := CreateActivity("Create", nObj)
+ MakeActivityRequest(activity)
+ }
+
+ var id string
+ re := regexp.MustCompile("\\w+$")
+ op := len(nObj.InReplyTo) - 1
+ if op >= 0 {
+ if nObj.InReplyTo[op].Id == "" {
+ id = re.FindString(nObj.Id)
+ } else {
+ id = re.FindString(nObj.InReplyTo[op].Id)
+ }
+ }
+
+ w.WriteHeader(http.StatusOK)
+ w.Write([]byte(id))
+ }
+
+
+
+ } else {
+ activity = GetActivityFromJson(r, db)
+ if IsActivityLocal(db, activity) {
+ switch activity.Type {
+ case "Create":
+ if(true) {
+ object = GetObjectFromActivity(activity)
+ writeObjectToDB(db, object)
+ w.WriteHeader(http.StatusCreated)
+ w.Header().Set("Location", object.Id)
+ } else {
+ w.WriteHeader(http.StatusUnauthorized)
+ w.Write([]byte(""))
+ }
+
+ case "Follow":
+ var validActor bool
+ var validLocalActor bool
+
+ _, validActor = IsValidActor(activity.Object.Id)
+ validLocalActor = (activity.Actor.Id == actor.Id) || (activity.Object.Id == actor.Id)
+ verification := GetVerificationByCode(db, activity.Auth)
+
+ var rActivity Activity
+
+ if validActor && validLocalActor && verification.Board == activity.Actor.Id {
+ rActivity = AcceptFollow(activity, actor)
+ } else {
+ rActivity = RejectFollow(activity, actor)
+ rActivity.Summary = "No valid actor or Actor is not located here"
+ }
+
+ if rActivity.Type == "Accept" {
+ rActivity.Summary = SetActorFollowDB(db, activity, actor.Id).Summary
+ }
+
+ enc, _ := json.MarshalIndent(rActivity, "", "\t")
+
+ if rActivity.Type == "Reject" {
+ w.WriteHeader(http.StatusBadRequest)
+ }
+
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ w.Write(enc)
+
+ case "Delete":
+ fmt.Println("This is a delete")
+ w.WriteHeader(http.StatusBadRequest)
+ w.Write([]byte("could not process activity"))
+
+ case "Note":
+ fmt.Println("This is a note")
+ w.WriteHeader(http.StatusBadRequest)
+ w.Write([]byte("could not process activity"))
+
+ case "New":
+ fmt.Println("Added new Board")
+ name := activity.Object.Actor.Name
+ prefname := activity.Object.Actor.PreferredUsername
+ summary := activity.Object.Actor.Summary
+ restricted := activity.Object.Actor.Restricted
+
+ actor := CreateNewBoardDB(db, *CreateNewActor(name, prefname, summary, authReq, restricted))
+
+ if actor.Id != "" {
+ j, _ := json.Marshal(&actor)
+ w.Write([]byte(j))
+ return
+ }
+
+ w.WriteHeader(http.StatusBadRequest)
+ w.Write([]byte(""))
+
+ default:
+ w.WriteHeader(http.StatusBadRequest)
+ w.Write([]byte("could not process activity"))
+ }
+ } else {
+ fmt.Println("is NOT activity")
+ w.WriteHeader(http.StatusBadRequest)
+ w.Write([]byte("could not process activity"))
+ }
+ }
+}
+
+func ObjectFromJson(r *http.Request, obj ObjectBase) ObjectBase {
+ body, _ := ioutil.ReadAll(r.Body)
+
+ var respActivity ActivityRaw
+
+ err := json.Unmarshal(body, &respActivity)
+
+ CheckError(err, "error with object from json")
+
+ if HasContextFromJson(respActivity.AtContextRaw.Context) {
+ var jObj ObjectBase
+ jObj = GetObjectFromJson(respActivity.ObjectRaw)
+ jObj.To = GetToFromJson(respActivity.ToRaw)
+ jObj.Cc = GetToFromJson(respActivity.CcRaw)
+ }
+
+ return obj
+}
+
+func GetObjectFromJson(obj []byte) ObjectBase {
+ var generic interface{}
+
+ err := json.Unmarshal(obj, &generic)
+
+ CheckError(err, "error with getting obj from json")
+
+ t := reflect.TypeOf(generic)
+
+ var nObj ObjectBase
+ if t != nil {
+ switch t.String() {
+ case "[]interface {}":
+ var lObj ObjectBase
+ var arrContext ObjectArray
+ err = json.Unmarshal(obj, &arrContext.Object)
+ CheckError(err, "error with []interface{} oject from json")
+ if len(arrContext.Object) > 0 {
+ lObj = arrContext.Object[0]
+ }
+ nObj = lObj
+ break
+
+ case "map[string]interface {}":
+ var arrContext Object
+ err = json.Unmarshal(obj, &arrContext.Object)
+ CheckError(err, "error with object from json")
+ nObj = *arrContext.Object
+ break
+
+ case "string":
+ var lObj ObjectBase
+ var arrContext ObjectString
+ err = json.Unmarshal(obj, &arrContext.Object)
+ CheckError(err, "error with string object from json")
+ lObj.Id = arrContext.Object
+ nObj = lObj
+ break
+ }
+ }
+
+ return nObj
+}
+
+func GetActorFromJson(actor []byte) Actor{
+ var generic interface{}
+ var nActor Actor
+ err := json.Unmarshal(actor, &generic)
+
+ if err != nil {
+ return nActor
+ }
+
+ t := reflect.TypeOf(generic)
+ if t != nil {
+ switch t.String() {
+ case "map[string]interface {}":
+ err = json.Unmarshal(actor, &nActor)
+ CheckError(err, "error with To []interface{}")
+
+ case "string":
+ var str string
+ err = json.Unmarshal(actor, &str)
+ CheckError(err, "error with To string")
+ nActor.Id = str
+ }
+
+ return nActor
+ }
+
+ return nActor
+}
+
+func GetToFromJson(to []byte) []string {
+ var generic interface{}
+
+ err := json.Unmarshal(to, &generic)
+
+ if err != nil {
+ return nil
+ }
+
+ t := reflect.TypeOf(generic)
+
+ if t != nil {
+ var nStr []string
+ switch t.String() {
+ case "[]interface {}":
+ err = json.Unmarshal(to, &nStr)
+ CheckError(err, "error with To []interface{}")
+ return nStr
+
+ case "string":
+ var str string
+ err = json.Unmarshal(to, &str)
+ CheckError(err, "error with To string")
+ nStr = append(nStr, str)
+ return nStr
+ }
+ }
+
+ return nil
+}
+
+func HasContextFromJson(context []byte) bool {
+ var generic interface{}
+
+ err := json.Unmarshal(context, &generic)
+
+ CheckError(err, "error with getting context")
+
+ t := reflect.TypeOf(generic)
+
+ hasContext := false
+
+ switch t.String() {
+ case "[]interface {}":
+ var arrContext AtContextArray
+ err = json.Unmarshal(context, &arrContext.Context)
+ CheckError(err, "error with []interface{}")
+ if len(arrContext.Context) > 0 {
+ if arrContext.Context[0] == "https://www.w3.org/ns/activitystreams" {
+ hasContext = true
+ }
+ }
+ case "string":
+ var arrContext AtContextString
+ err = json.Unmarshal(context, &arrContext.Context)
+ CheckError(err, "error with string")
+ if arrContext.Context == "https://www.w3.org/ns/activitystreams" {
+ hasContext = true
+ }
+ }
+
+ return hasContext
+}
+
+func ObjectFromForm(r *http.Request, db *sql.DB, obj ObjectBase) ObjectBase {
+
+ file, header, _ := r.FormFile("file")
+
+ if file != nil {
+ defer file.Close()
+
+ var tempFile = new(os.File)
+ obj.Attachment, tempFile = CreateAttachmentObject(file, header)
+
+ defer tempFile.Close();
+
+ fileBytes, _ := ioutil.ReadAll(file)
+
+ tempFile.Write(fileBytes)
+ }
+
+ obj.AttributedTo = EscapeString(r.FormValue("name"))
+ obj.Name = EscapeString(r.FormValue("subject"))
+ obj.Content = EscapeString(r.FormValue("comment"))
+
+ obj = ParseOptions(r, obj)
+
+ var originalPost ObjectBase
+ originalPost.Id = EscapeString(r.FormValue("inReplyTo"))
+
+ obj.InReplyTo = append(obj.InReplyTo, originalPost)
+
+ var activity Activity
+
+ activity.To = append(activity.To, originalPost.Id)
+
+ if originalPost.Id != "" {
+ if !IsActivityLocal(db, activity) {
+ id := GetActorFromID(originalPost.Id).Id
+
+ obj.To = append(obj.To, GetActor(id).Id)
+ }
+ }
+
+ replyingTo := ParseCommentForReplies(r.FormValue("comment"))
+
+ for _, e := range replyingTo {
+
+ has := false
+
+ for _, f := range obj.InReplyTo {
+ if e.Id == f.Id {
+ has = true
+ break
+ }
+ }
+
+ if !has {
+ obj.InReplyTo = append(obj.InReplyTo, e)
+
+ var activity Activity
+
+ activity.To = append(activity.To, e.Id)
+
+ if !IsActivityLocal(db, activity) {
+ id := GetActorFromID(e.Id).Id
+
+ obj.To = append(obj.To, GetActor(id).Id)
+ }
+ }
+ }
+
+ return obj
+}
+
+
+func ParseOptions(r *http.Request, obj ObjectBase) ObjectBase {
+ options := EscapeString(r.FormValue("options"))
+ if options != "" {
+ option := strings.Split(options, ";")
+ email := regexp.MustCompile(".+@.+\\..+")
+ wallet := regexp.MustCompile("wallet:.+")
+ delete := regexp.MustCompile("delete:.+")
+ for _, e := range option {
+ if e == "noko" {
+ obj.Option = append(obj.Option, "noko")
+ } else if e == "sage" {
+ obj.Option = append(obj.Option, "sage")
+ } else if e == "nokosage" {
+ obj.Option = append(obj.Option, "nokosage")
+ } else if email.MatchString(e) {
+ obj.Option = append(obj.Option, "email:" + e)
+ } else if wallet.MatchString(e) {
+ obj.Option = append(obj.Option, "wallet")
+ var wallet CryptoCur
+ value := strings.Split(e, ":")
+ wallet.Type = value[0]
+ wallet.Address = value[1]
+ obj.Wallet = append(obj.Wallet, wallet)
+ } else if delete.MatchString(e) {
+ obj.Option = append(obj.Option, e)
+ }
+ }
+ }
+
+ return obj
+}
+
+func GetActivityFromJson(r *http.Request, db *sql.DB) Activity {
+ body, _ := ioutil.ReadAll(r.Body)
+
+ var respActivity ActivityRaw
+
+ var nActivity Activity
+
+ var nType string
+
+ err := json.Unmarshal(body, &respActivity)
+
+ CheckError(err, "error with activity from json")
+
+ if HasContextFromJson(respActivity.AtContextRaw.Context) {
+ var jObj ObjectBase
+
+ if respActivity.Type == "Note" {
+ jObj = GetObjectFromJson(body)
+ jObj.AtContext.Context = ""
+ nType = "Create"
+ } else {
+ jObj = GetObjectFromJson(respActivity.ObjectRaw)
+ nType = respActivity.Type
+ }
+
+ actor := GetActorFromJson(respActivity.ActorRaw)
+ to := GetToFromJson(respActivity.ToRaw)
+ cc := GetToFromJson(respActivity.CcRaw)
+
+ jObj.AttributedTo = actor.Id
+
+ nActivity.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+ nActivity.Type = nType
+ nActivity.Actor = &actor
+ nActivity.Published = respActivity.Published
+ nActivity.Auth = respActivity.Auth
+
+ if len(to) > 0 {
+ nActivity.To = to
+ }
+
+ if len(cc) > 0 {
+ nActivity.Cc = cc
+ }
+
+ nActivity.Name = respActivity.Name
+ nActivity.Object = &jObj
+ }
+
+ return nActivity
+}
+
+func CheckCaptcha(db *sql.DB, captcha string) bool {
+ parts := strings.Split(captcha, ":")
+ path := "public/" + parts[0] + ".png"
+ code := GetCaptchaCodeDB(db, path)
+
+ DeleteCaptchaCodeDB(db, path)
+ CreateNewCaptcha(db)
+
+ if (code == strings.ToUpper(parts[1])) {
+ return true
+ }
+
+ return false
+}
+
+func ParseInboxRequest(w http.ResponseWriter, r *http.Request, db *sql.DB) {
+ activity := GetActivityFromJson(r, db)
+
+ switch(activity.Type) {
+ case "Create":
+ for _, e := range activity.Object.InReplyTo {
+ if IsObjectLocal(db, e.Id) {
+ WriteObjectReplyToLocalDB(db, activity.Object.Id, e.Id)
+ }
+ }
+ break
+
+ case "Follow":
+ for _, e := range activity.To {
+ if IsObjectLocal(db, e) {
+ nActivity := SetActorFollowingDB(db, activity)
+ j, _ := json.Marshal(&nActivity)
+ w.Write([]byte(j))
+ }
+ }
+ break
+ }
+}
+
+func MakeActivityFollowingReq(w http.ResponseWriter, r *http.Request, activity Activity) bool {
+ actor := GetActor(activity.Object.Id)
+
+ resp, err := http.NewRequest("POST", actor.Inbox, nil)
+
+ CheckError(err, "Cannot make new get request to actor inbox for following req")
+
+ defer resp.Body.Close()
+
+ body, _ := ioutil.ReadAll(resp.Body)
+
+ var respActivity Activity
+
+ err = json.Unmarshal(body, &respActivity)
+
+ if respActivity.Type == "Accept" {
+ return true
+ }
+
+ return false
+}