diff options
author | FChannel <=> | 2021-01-22 21:12:26 -0800 |
---|---|---|
committer | FChannel <=> | 2021-01-22 21:12:26 -0800 |
commit | 2566e314e8351ffbceae9a2688d90a5c811d49e5 (patch) | |
tree | e802622593c540265e464beecf76696b65e229ed /client.go | |
parent | 626fee35bacd68baf6e9bb38ca71d88fff700b13 (diff) |
client to server conversion
Diffstat (limited to 'client.go')
-rw-r--r-- | client.go | 731 |
1 files changed, 731 insertions, 0 deletions
diff --git a/client.go b/client.go new file mode 100644 index 0000000..976eb31 --- /dev/null +++ b/client.go @@ -0,0 +1,731 @@ +package main + +import "fmt" +import "net/http" +import "html/template" +import "database/sql" +import _ "github.com/lib/pq" +import "strings" +import "strconv" +import "math" +import "sort" +import "regexp" +import "io/ioutil" +import "encoding/json" +import "os" + +var Key *string = new(string) + +var Boards *[]ObjectBase = new([]ObjectBase) + +type Board struct{ + Name string + Actor string + Summary string + PrefName string + InReplyTo string + Location string + To string + RedirectTo string + Captcha string + CaptchaCode string + ModCred string + Domain string + TP string +} + +type PageData struct { + Title string + Message string + Board Board + Pages []int + CurrentPage int + TotalPage int + Boards []Board + Posts []ObjectBase + Key string +} + +type AdminPage struct { + Title string + Board Board + Key string + Actor string + Boards []Board + Following []string + Followers []string + Reported []Report + Domain string +} + +type Report struct { + ID string + Count int +} + +type Removed struct { + ID string + Type string + Board string +} + +func IndexGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { + t := template.Must(template.ParseFiles("./static/main.html", "./static/index.html")) + + actor := GetActorFromDB(db, Domain) + + var boardCollection []Board + + for _, e := range *Boards { + var board Board + boardActor := GetActor(e.Id) + board.Name = "/" + boardActor.Name + "/" + board.PrefName = boardActor.PreferredUsername + board.Location = "/" + boardActor.Name + boardCollection = append(boardCollection, board) + } + + var data PageData + data.Title = "Welcome to " + actor.PreferredUsername + data.Message = fmt.Sprintf("This is the client for the image board %s. The current version of the code running the server and client is volatile, expect a bumpy ride for the time being. Get the server and client code here https://github.com/FChannel0", Domain) + data.Boards = boardCollection + data.Board.Name = "" + data.Key = *Key + data.Board.Domain = Domain + data.Board.ModCred, _ = GetPasswordFromSession(r) + + t.ExecuteTemplate(w, "layout", data) +} + +func OutboxGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Collection){ + + t := template.Must(template.ParseFiles("./static/main.html", "./static/nposts.html", "./static/top.html", "./static/bottom.html", "./static/posts.html")) + + actor := collection.Actor + + postNum := strings.Replace(r.URL.EscapedPath(), "/" + actor.Name + "/", "", 1) + + page, _ := strconv.Atoi(postNum) + + var returnData PageData + + returnData.Board.Name = actor.Name + returnData.Board.PrefName = actor.PreferredUsername + returnData.Board.Summary = actor.Summary + returnData.Board.InReplyTo = "" + returnData.Board.To = actor.Outbox + returnData.Board.Actor = actor.Id + returnData.Board.ModCred, _ = GetPasswordFromSession(r) + returnData.Board.Domain = Domain + returnData.CurrentPage = page + + returnData.Board.Captcha = GetCaptcha(*actor) + returnData.Board.CaptchaCode = GetCaptchaCode(returnData.Board.Captcha) + + returnData.Title = "/" + actor.Name + "/ - " + actor.PreferredUsername + + returnData.Key = *Key + + var mergeCollection Collection + + for _, e := range collection.OrderedItems { + if e.Type != "Tombstone" { + mergeCollection.OrderedItems = append(mergeCollection.OrderedItems, e) + } + } + + domainURL := GetDomainURL(*actor) + + if domainURL == Domain { + followCol := GetObjectsFromFollow(*actor) + for _, e := range followCol { + if e.Type != "Tombstone" { + mergeCollection.OrderedItems = append(mergeCollection.OrderedItems, e) + } + } + } + + DeleteRemovedPosts(db, &mergeCollection) + DeleteTombstoneReplies(&mergeCollection) + + for i, _ := range mergeCollection.OrderedItems { + sort.Sort(ObjectBaseSortAsc(mergeCollection.OrderedItems[i].Replies.OrderedItems)) + } + + DeleteTombstonePosts(&mergeCollection) + sort.Sort(ObjectBaseSortDesc(mergeCollection.OrderedItems)) + + + + returnData.Boards = GetBoardCollection(db) + + offset := 8 + start := page * offset + for i := 0; i < offset; i++ { + length := len(mergeCollection.OrderedItems) + current := start + i + if(current < length) { + returnData.Posts = append(returnData.Posts, mergeCollection.OrderedItems[current]) + } + } + + + for i, e := range returnData.Posts { + var replies []ObjectBase + for i := 0; i < 5; i++ { + cur := len(e.Replies.OrderedItems) - i - 1 + if cur > -1 { + replies = append(replies, e.Replies.OrderedItems[cur]) + } + } + + var orderedReplies []ObjectBase + for i := 0; i < 5; i++ { + cur := len(replies) - i - 1 + if cur > -1 { + orderedReplies = append(orderedReplies, replies[cur]) + } + } + returnData.Posts[i].Replies.OrderedItems = orderedReplies + } + + var pages []int + pageLimit := math.Round(float64(len(mergeCollection.OrderedItems) / offset)) + for i := 0.0; i <= pageLimit; i++ { + pages = append(pages, int(i)) + } + + returnData.Pages = pages + returnData.TotalPage = len(returnData.Pages) - 1 + + t.ExecuteTemplate(w, "layout", returnData) +} + +func CatalogGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Collection){ + + t := template.Must(template.ParseFiles("./static/main.html", "./static/ncatalog.html", "./static/top.html")) + + actor := collection.Actor + + var mergeCollection Collection + + for _, e := range collection.OrderedItems { + mergeCollection.OrderedItems = append(mergeCollection.OrderedItems, e) + } + + domainURL := GetDomainURL(*actor) + + if domainURL == Domain { + followCol := GetObjectsFromFollow(*actor) + for _, e := range followCol { + + mergeCollection.OrderedItems = append(mergeCollection.OrderedItems, e) + } + } + + DeleteRemovedPosts(db, &mergeCollection) + DeleteTombstonePosts(&mergeCollection) + + sort.Sort(ObjectBaseSortDesc(mergeCollection.OrderedItems)) + + var returnData PageData + returnData.Board.Name = actor.Name + returnData.Board.PrefName = actor.PreferredUsername + returnData.Board.InReplyTo = "" + returnData.Board.To = actor.Outbox + returnData.Board.Actor = actor.Id + returnData.Board.Summary = actor.Summary + returnData.Board.ModCred, _ = GetPasswordFromSession(r) + returnData.Board.Domain = Domain + returnData.Key = *Key + + returnData.Board.Captcha = GetCaptcha(*actor) + returnData.Board.CaptchaCode = GetCaptchaCode(returnData.Board.Captcha) + + returnData.Title = "/" + actor.Name + "/ - " + actor.PreferredUsername + + returnData.Boards = GetBoardCollection(db) + + returnData.Posts = mergeCollection.OrderedItems + + t.ExecuteTemplate(w, "layout", returnData) +} + +func PostGet(w http.ResponseWriter, r *http.Request, db *sql.DB){ + + t := template.Must(template.ParseFiles("./static/main.html", "./static/npost.html", "./static/top.html", "./static/bottom.html", "./static/posts.html")) + + path := r.URL.Path + actor := GetActorFromPath(db, path, "/") + re := regexp.MustCompile("\\w+$") + postId := re.FindString(path) + + inReplyTo := actor.Id + "/" + postId + + var returnData PageData + + returnData.Board.Name = actor.Name + returnData.Board.PrefName = actor.PreferredUsername + returnData.Board.To = actor.Outbox + returnData.Board.Actor = actor.Id + returnData.Board.Summary = actor.Summary + returnData.Board.ModCred, _ = GetPasswordFromSession(r) + returnData.Board.Domain = Domain + + + if GetDomainURL(actor) != "" { + returnData.Board.Captcha = GetCaptcha(actor) + returnData.Board.CaptchaCode = GetCaptchaCode(returnData.Board.Captcha) + } + + returnData.Title = "/" + returnData.Board.Name + "/ - " + returnData.Board.PrefName + + returnData.Key = *Key + + returnData.Boards = GetBoardCollection(db) + + re = regexp.MustCompile("f\\w+-\\w+") + + if re.MatchString(path) { + name := GetActorFollowNameFromPath(path) + followActors := GetActorsFollowFromName(actor, name) + followCollection := GetActorsFollowPostFromId(followActors, postId) + + DeleteRemovedPosts(db, &followCollection) + DeleteTombstoneReplies(&followCollection) + + for i, _ := range followCollection.OrderedItems { + sort.Sort(ObjectBaseSortAsc(followCollection.OrderedItems[i].Replies.OrderedItems)) + } + + if len(followCollection.OrderedItems) > 0 { + returnData.Board.InReplyTo = followCollection.OrderedItems[0].Id + returnData.Posts = append(returnData.Posts, followCollection.OrderedItems[0]) + sort.Sort(ObjectBaseSortAsc(returnData.Posts[0].Replies.OrderedItems)) + } + + } else { + + returnData.Board.InReplyTo = inReplyTo + collection := GetActorCollection(inReplyTo) + + DeleteRemovedPosts(db, &collection) + + for i, e := range collection.OrderedItems { + var replies CollectionBase + for _, k := range e.Replies.OrderedItems { + if k.Type != "Tombstone" { + replies.OrderedItems = append(replies.OrderedItems, k) + } else { + collection.OrderedItems[i].Replies.TotalItems = collection.OrderedItems[i].Replies.TotalItems - 1 + if k.Preview.Id != "" { + collection.OrderedItems[i].Replies.TotalImgs = collection.OrderedItems[i].Replies.TotalImgs - 1 + } + } + } + collection.TotalItems = collection.OrderedItems[i].Replies.TotalItems + collection.TotalImgs = collection.OrderedItems[i].Replies.TotalImgs + collection.OrderedItems[i].Replies = &replies + sort.Sort(ObjectBaseSortAsc(e.Replies.OrderedItems)) + } + + if len(collection.OrderedItems) > 0 { + returnData.Posts = append(returnData.Posts, collection.OrderedItems[0]) + sort.Sort(ObjectBaseSortAsc(returnData.Posts[0].Replies.OrderedItems)) + } + } + + t.ExecuteTemplate(w, "layout", returnData) +} + +func GetRemoteActor(id string) Actor { + + var respActor Actor + + id = StripTransferProtocol(id) + + req, err := http.NewRequest("GET", "http://" + id, nil) + + CheckError(err, "error with getting actor req") + + req.Header.Set("Accept", activitystreams) + + resp, err := http.DefaultClient.Do(req) + + if err != nil || resp.StatusCode != 200 { + fmt.Println("could not get actor from " + id) + return respActor + } + + defer resp.Body.Close() + + body, _ := ioutil.ReadAll(resp.Body) + + err = json.Unmarshal(body, &respActor) + + CheckError(err, "error getting actor from body") + + return respActor +} + +func GetBoardCollection(db *sql.DB) []Board { + var collection []Board + for _, e := range *Boards { + var board Board + boardActor := GetActorFromDB(db, e.Id) + if boardActor.Id == "" { + boardActor = GetRemoteActor(e.Id) + } + board.Name = "/" + boardActor.Name + "/" + board.PrefName = boardActor.PreferredUsername + board.Location = "/" + boardActor.Name + collection = append(collection, board) + } + + return collection +} + +func WantToServe(db *sql.DB, actorName string) (Collection, bool) { + + var collection Collection + serve := false + + for _, e := range *Boards { + boardActor := GetActorFromDB(db, e.Id) + + if boardActor.Id == "" { + boardActor = GetActor(e.Id) + } + + if boardActor.Id == actorName { + serve = true + collection = GetActorCollection(boardActor.Outbox) + collection.Actor = &boardActor + } + } + + return collection, serve +} + +func StripTransferProtocol(value string) string { + re := regexp.MustCompile("(http://|https://)?(www.)?") + + value = re.ReplaceAllString(value, "") + + return value +} + +func GetCaptcha(actor Actor) string { + re := regexp.MustCompile("(https://|http://)?(www)?.+/") + + domainURL := re.FindString(actor.Id) + + re = regexp.MustCompile("/$") + + domainURL = re.ReplaceAllString(domainURL, "") + + resp, err := http.Get(domainURL + "/getcaptcha") + + CheckError(err, "error getting captcha") + + defer resp.Body.Close() + + body, _ := ioutil.ReadAll(resp.Body) + + return domainURL + "/" + string(body) +} + +func GetCaptchaCode(captcha string) string { + re := regexp.MustCompile("\\w+\\.\\w+$") + + code := re.FindString(captcha) + + re = regexp.MustCompile("\\w+") + + code = re.FindString(code) + + return code +} + +func GetDomainURL(actor Actor) string { + re := regexp.MustCompile("(https://|http://)?(www)?.+/") + + domainURL := re.FindString(actor.Id) + + re = regexp.MustCompile("/$") + + domainURL = re.ReplaceAllString(domainURL, "") + + return domainURL +} + +func DeleteTombstoneReplies(collection *Collection) { + + for i, e := range collection.OrderedItems { + var replies CollectionBase + for _, k := range e.Replies.OrderedItems { + if k.Type != "Tombstone" { + replies.OrderedItems = append(replies.OrderedItems, k) + } + } + + replies.TotalItems = collection.OrderedItems[i].Replies.TotalItems + replies.TotalImgs = collection.OrderedItems[i].Replies.TotalImgs + collection.OrderedItems[i].Replies = &replies + } +} + +func DeleteTombstonePosts(collection *Collection) { + var nColl Collection + + for _, e := range collection.OrderedItems { + if e.Type != "Tombstone" { + nColl.OrderedItems = append(nColl.OrderedItems, e) + } + } + collection.OrderedItems = nColl.OrderedItems +} + +func DeleteRemovedPosts(db *sql.DB, collection *Collection) { + + removed := GetLocalDeleteDB(db) + + for p, e := range collection.OrderedItems { + for _, j := range removed { + if e.Id == j.ID { + if j.Type == "attachment" { + collection.OrderedItems[p].Preview.Href = "/public/removed.png" + collection.OrderedItems[p].Preview.Name = "deleted" + collection.OrderedItems[p].Preview.MediaType = "image/png" + collection.OrderedItems[p].Attachment[0].Href = "/public/removed.png" + collection.OrderedItems[p].Attachment[0].Name = "deleted" + collection.OrderedItems[p].Attachment[0].MediaType = "image/png" + } else { + collection.OrderedItems[p].AttributedTo = "deleted" + collection.OrderedItems[p].Content = "" + collection.OrderedItems[p].Type = "Tombstone" + if collection.OrderedItems[p].Attachment != nil { + collection.OrderedItems[p].Preview.Href = "/public/removed.png" + collection.OrderedItems[p].Preview.Name = "deleted" + collection.OrderedItems[p].Preview.MediaType = "image/png" + collection.OrderedItems[p].Attachment[0].Href = "/public/removed.png" + collection.OrderedItems[p].Attachment[0].Name = "deleted" + collection.OrderedItems[p].Attachment[0].MediaType = "image/png" + } + } + } + } + + for i, r := range e.Replies.OrderedItems { + for _, k := range removed { + if r.Id == k.ID { + if k.Type == "attachment" { + e.Replies.OrderedItems[i].Preview.Href = "/public/removed.png" + e.Replies.OrderedItems[i].Preview.Name = "deleted" + e.Replies.OrderedItems[i].Preview.MediaType = "image/png" + e.Replies.OrderedItems[i].Attachment[0].Href = "/public/removed.png" + e.Replies.OrderedItems[i].Attachment[0].Name = "deleted" + e.Replies.OrderedItems[i].Attachment[0].MediaType = "image/png" + collection.OrderedItems[p].Replies.TotalImgs = collection.OrderedItems[p].Replies.TotalImgs - 1 + } else { + e.Replies.OrderedItems[i].AttributedTo = "deleted" + e.Replies.OrderedItems[i].Content = "" + e.Replies.OrderedItems[i].Type = "Tombstone" + if e.Replies.OrderedItems[i].Attachment != nil { + e.Replies.OrderedItems[i].Preview.Href = "/public/removed.png" + e.Replies.OrderedItems[i].Preview.Name = "deleted" + e.Replies.OrderedItems[i].Preview.MediaType = "image/png" + e.Replies.OrderedItems[i].Attachment[0].Name = "deleted" + e.Replies.OrderedItems[i].Attachment[0].Href = "/public/removed.png" + e.Replies.OrderedItems[i].Attachment[0].MediaType = "image/png" + collection.OrderedItems[p].Replies.TotalImgs = collection.OrderedItems[p].Replies.TotalImgs - 1 + } + collection.OrderedItems[p].Replies.TotalItems = collection.OrderedItems[p].Replies.TotalItems - 1 + } + } + } + } + } +} + +func CreateLocalDeleteDB(db *sql.DB, id string, _type string) { + query := fmt.Sprintf("select id from removed where id='%s'", id) + + rows, err := db.Query(query) + + CheckError(err, "could not query removed") + + defer rows.Close() + + if rows.Next() { + var i string + + rows.Scan(&i) + + if i != "" { + query := fmt.Sprintf("update removed set type='%s' where id='%s'", _type, id) + + _, err := db.Exec(query) + + CheckError(err, "Could not update removed post") + + } + } else { + query := fmt.Sprintf("insert into removed (id, type) values ('%s', '%s')", id, _type) + + _, err := db.Exec(query) + + CheckError(err, "Could not insert removed post") + } +} + +func GetLocalDeleteDB(db *sql.DB) []Removed { + var deleted []Removed + + query := fmt.Sprintf("select id, type from removed") + + rows, err := db.Query(query) + + CheckError(err, "could not query removed") + + defer rows.Close() + + for rows.Next() { + var r Removed + + rows.Scan(&r.ID, &r.Type) + + deleted = append(deleted, r) + } + + return deleted +} + +func CreateLocalReportDB(db *sql.DB, id string, board string) { + query := fmt.Sprintf("select id, count from reported where id='%s' and board='%s'", id, board) + + rows, err := db.Query(query) + + CheckError(err, "could not query reported") + + defer rows.Close() + + if rows.Next() { + var i string + var count int + + rows.Scan(&i, &count) + + if i != "" { + count = count + 1 + query := fmt.Sprintf("update reported set count='%d' where id='%s'", count, id) + + _, err := db.Exec(query) + + CheckError(err, "Could not update reported post") + } + } else { + query := fmt.Sprintf("insert into reported (id, count, board) values ('%s', '%d', '%s')", id, 1, board) + + _, err := db.Exec(query) + + CheckError(err, "Could not insert reported post") + } + +} + +func GetLocalReportDB(db *sql.DB, board string) []Report { + var reported []Report + + query := fmt.Sprintf("select id, count from reported where board='%s'", board) + + rows, err := db.Query(query) + + CheckError(err, "could not query reported") + + defer rows.Close() + + for rows.Next() { + var r Report + + rows.Scan(&r.ID, &r.Count) + + reported = append(reported, r) + } + + return reported +} + +func CloseLocalReportDB(db *sql.DB, id string, board string) { + query := fmt.Sprintf("delete from reported where id='%s' and board='%s'", id, board) + + _, err := db.Exec(query) + + CheckError(err, "Could not delete local report from db") +} + +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 GetActorsFollowFromName(actor Actor, name string) []Actor { + var followingActors []Actor + follow := GetActorCollection(actor.Following) + + re := regexp.MustCompile("\\w+?$") + + for _, e := range follow.Items { + if re.FindString(e.Id) == name { + actor := GetActor(e.Id) + followingActors = append(followingActors, actor) + } + } + + return followingActors +} + +func GetActorsFollowPostFromId(actors []Actor, id string) Collection{ + var collection Collection + + for _, e := range actors { + tempCol := GetActorCollection(e.Id + "/" + id) + if len(tempCol.OrderedItems) > 0 { + collection = tempCol + } + } + + return collection +} + +func CreateClientKey() string{ + + file, err := os.Create("clientkey") + + CheckError(err, "could not create client key in file") + + defer file.Close() + + key := CreateKey(32) + file.WriteString(key) + return key +} + +type ObjectBaseSortDesc []ObjectBase +func (a ObjectBaseSortDesc) Len() int { return len(a) } +func (a ObjectBaseSortDesc) Less(i, j int) bool { return a[i].Updated > a[j].Updated } +func (a ObjectBaseSortDesc) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +type ObjectBaseSortAsc []ObjectBase +func (a ObjectBaseSortAsc) Len() int { return len(a) } +func (a ObjectBaseSortAsc) Less(i, j int) bool { return a[i].Published < a[j].Published } +func (a ObjectBaseSortAsc) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + |