{{ parseContent $board.Actor $opId .Content $thread }}
+From 48fefb76c0a908cc3fa00abc9c090ce3ac8cb560 Mon Sep 17 00:00:00 2001 From: FChannel <> Date: Sun, 24 Oct 2021 10:40:45 -0700 Subject: gofiber conversion, index, board posts, board post hooked up --- README.md | 6 - client.go | 170 ++--- go.mod | 3 +- go.sum | 610 ++++++++++++++- main.go | 1585 +++++++-------------------------------- session.go | 24 + views/css/themes/default.css | 249 ++++++ views/css/themes/gruvbox.css | 235 ++++++ views/index.html | 53 ++ views/js/footerscript.js | 44 ++ views/js/posts.js | 344 +++++++++ views/js/themes.js | 40 + views/js/timer.js | 38 + views/layouts/main.html | 50 ++ views/npost.html | 66 ++ views/nposts.html | 70 ++ views/partials/bottom.html | 48 ++ views/partials/footer.html | 13 + views/partials/posts.html | 122 +++ views/partials/postscripts.html | 3 + views/partials/top.html | 128 ++++ 21 files changed, 2441 insertions(+), 1460 deletions(-) create mode 100644 views/css/themes/default.css create mode 100644 views/css/themes/gruvbox.css create mode 100644 views/index.html create mode 100644 views/js/footerscript.js create mode 100644 views/js/posts.js create mode 100644 views/js/themes.js create mode 100644 views/js/timer.js create mode 100644 views/layouts/main.html create mode 100644 views/npost.html create mode 100644 views/nposts.html create mode 100644 views/partials/bottom.html create mode 100644 views/partials/footer.html create mode 100644 views/partials/posts.html create mode 100644 views/partials/postscripts.html create mode 100644 views/partials/top.html diff --git a/README.md b/README.md index 4d4bba2..af813db 100644 --- a/README.md +++ b/README.md @@ -163,9 +163,3 @@ instanceport:PORT GOES HERE ``` See #12 for more details. - -# Support - -Any support is appreciated all funds go to hosting and development of the project - -XMR - 85ma5KYR8Jk8zhGospQ8DeMNUrY74rQqEgiiPHvKHbowa37TAa5MLUD8RBaupw5oAxWmpFDrSAxsDbeXcfoAwiZF69mq4CE diff --git a/client.go b/client.go index e306b10..274ad64 100644 --- a/client.go +++ b/client.go @@ -3,6 +3,7 @@ package main import ( "database/sql" "fmt" + "github.com/gofiber/fiber/v2" _ "github.com/lib/pq" "html/template" "log" @@ -120,13 +121,9 @@ func timeToUnix(t time.Time) string { return fmt.Sprint(t.Unix()) } -func IndexGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { - t := template.Must(template.New("").Funcs(template.FuncMap{ - "mod": mod, - "sub": sub, - "unixtoreadable": unixToReadable}).ParseFiles("./static/main.html", "./static/index.html")) +func IndexGet(c *fiber.Ctx) error { - actor := GetActorFromDB(db, Domain) + actor := GetActorFromDB(DB, Domain) var data PageData data.Title = "Welcome to " + actor.PreferredUsername @@ -135,7 +132,7 @@ func IndexGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { data.Board.Name = "" data.Key = *Key data.Board.Domain = Domain - data.Board.ModCred, _ = GetPasswordFromSession(r) + data.Board.ModCred, _ = GetPasswordFromCtx(c) data.Board.Actor = actor data.Board.Post.Actor = actor.Id data.Board.Restricted = actor.Restricted @@ -152,18 +149,15 @@ func IndexGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { data.InstanceIndex = col.Items } - data.NewsItems = getNewsFromDB(db, 3) + data.NewsItems = getNewsFromDB(DB, 3) data.Themes = &Themes - if cookie, err := r.Cookie("theme"); err == nil { - data.ThemeCookie = strings.SplitN(cookie.String(), "=", 2)[1] - } - err := t.ExecuteTemplate(w, "layout", data) - if err != nil { - // TODO: actual error handler - log.Printf("IndexGet: %s\n", err) - } + data.ThemeCookie = GetThemeCookie(c) + + return c.Render("index", fiber.Map{ + "page": data, + }, "layouts/main") } func NewsGet(w http.ResponseWriter, r *http.Request, db *sql.DB, timestamp int) { @@ -241,53 +235,16 @@ func AllNewsGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { } } -func OutboxGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Collection) { - t := template.Must(template.New("").Funcs(template.FuncMap{ - "proxy": func(url string) string { - return MediaProxy(url) - }, - "short": func(actorName string, url string) string { - return shortURL(actorName, url) - }, - "parseAttachment": func(obj ObjectBase, catalog bool) template.HTML { - return ParseAttachment(obj, catalog) - }, - "parseContent": func(board Actor, op string, content string, thread ObjectBase) template.HTML { - return ParseContent(db, board, op, content, thread) - }, - "shortImg": func(url string) string { - return ShortImg(url) - }, - "convertSize": func(size int64) string { - return ConvertSize(size) - }, - "isOnion": func(url string) bool { - return IsOnion(url) - }, - "showArchive": func() bool { - col := GetActorCollectionDBTypeLimit(db, collection.Actor.Id, "Archive", 1) +func OutboxGet(c *fiber.Ctx) error { + collection, valid := WantToServePage(DB, c.Params("actor"), 0) - if len(col.OrderedItems) > 0 { - return true - } - return false - }, - "parseReplyLink": func(actorId string, op string, id string, content string) template.HTML { - actor := FingerActor(actorId) - title := strings.ReplaceAll(ParseLinkTitle(actor.Id, op, content), `/\<`, ">") - link := ">>" + shortURL(actor.Outbox, id) + "" - return template.HTML(link) - }, - "add": func(i, j int) int { - return i + j - }, - "timeToReadableLong": timeToReadableLong, - "timeToUnix": timeToUnix, - "sub": sub}).ParseFiles("./static/main.html", "./static/nposts.html", "./static/top.html", "./static/bottom.html", "./static/posts.html")) + if !valid { + return c.SendString("404") + } actor := collection.Actor - postNum := r.URL.Query().Get("page") + postNum := c.Query("page") page, _ := strconv.Atoi(postNum) @@ -299,7 +256,7 @@ func OutboxGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Co returnData.Board.InReplyTo = "" returnData.Board.To = actor.Outbox returnData.Board.Actor = *actor - returnData.Board.ModCred, _ = GetPasswordFromSession(r) + returnData.Board.ModCred, _ = GetPasswordFromCtx(c) returnData.Board.Domain = Domain returnData.Board.Restricted = actor.Restricted returnData.CurrentPage = page @@ -307,7 +264,7 @@ func OutboxGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Co returnData.Board.Post.Actor = actor.Id - returnData.Board.Captcha = Domain + "/" + GetRandomCaptcha(db) + returnData.Board.Captcha = Domain + "/" + GetRandomCaptcha(DB) returnData.Board.CaptchaCode = GetCaptchaCode(returnData.Board.Captcha) returnData.Title = "/" + actor.Name + "/ - " + actor.PreferredUsername @@ -333,15 +290,12 @@ func OutboxGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Co returnData.TotalPage = len(returnData.Pages) - 1 returnData.Themes = &Themes - if cookie, err := r.Cookie("theme"); err == nil { - returnData.ThemeCookie = strings.SplitN(cookie.String(), "=", 2)[1] - } - err := t.ExecuteTemplate(w, "layout", returnData) - if err != nil { - // TODO: actual error handler - log.Printf("OutboxGet: %s\n", err) - } + returnData.ThemeCookie = GetThemeCookie(c) + + return c.Render("nposts", fiber.Map{ + "page": returnData, + }, "layouts/main") } func CatalogGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Collection) { @@ -465,43 +419,10 @@ func ArchiveGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection C } } -func PostGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { - t := template.Must(template.New("").Funcs(template.FuncMap{ - "proxy": func(url string) string { - return MediaProxy(url) - }, - "short": func(actorName string, url string) string { - return shortURL(actorName, url) - }, - "parseAttachment": func(obj ObjectBase, catalog bool) template.HTML { - return ParseAttachment(obj, catalog) - }, - "parseContent": func(board Actor, op string, content string, thread ObjectBase) template.HTML { - return ParseContent(db, board, op, content, thread) - }, - "shortImg": func(url string) string { - return ShortImg(url) - }, - "convertSize": func(size int64) string { - return ConvertSize(size) - }, - "isOnion": func(url string) bool { - return IsOnion(url) - }, - "parseReplyLink": func(actorId string, op string, id string, content string) template.HTML { - actor := FingerActor(actorId) - title := strings.ReplaceAll(ParseLinkTitle(actor.Id, op, content), `/\<`, ">") - link := ">>" + shortURL(actor.Outbox, id) + "" - return template.HTML(link) - }, - "timeToReadableLong": timeToReadableLong, - "timeToUnix": timeToUnix, - "sub": sub}).ParseFiles("./static/main.html", "./static/npost.html", "./static/top.html", "./static/bottom.html", "./static/posts.html")) +func PostGet(c *fiber.Ctx) error { - path := r.URL.Path - actor := GetActorFromPath(db, path, "/") - re := regexp.MustCompile("\\w+$") - postId := re.FindString(path) + actor := GetActorByNameFromDB(DB, c.Params("actor")) + postId := c.Params("post") inReplyTo := actor.Id + "/" + postId @@ -511,15 +432,15 @@ func PostGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { returnData.Board.To = actor.Outbox returnData.Board.Actor = actor returnData.Board.Summary = actor.Summary - returnData.Board.ModCred, _ = GetPasswordFromSession(r) + returnData.Board.ModCred, _ = GetPasswordFromCtx(c) returnData.Board.Domain = Domain returnData.Board.Restricted = actor.Restricted returnData.ReturnTo = "feed" - returnData.Board.Captcha = Domain + "/" + GetRandomCaptcha(db) + returnData.Board.Captcha = Domain + "/" + GetRandomCaptcha(DB) returnData.Board.CaptchaCode = GetCaptchaCode(returnData.Board.Captcha) - returnData.Instance = GetActorFromDB(db, Domain) + returnData.Instance = GetActorFromDB(DB, Domain) returnData.Title = "/" + returnData.Board.Name + "/ - " + returnData.Board.PrefName @@ -527,12 +448,12 @@ func PostGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { returnData.Boards = Boards - re = regexp.MustCompile("f(\\w|[!@#$%^&*<>])+-(\\w|[!@#$%^&*<>])+") + re := regexp.MustCompile("f(\\w|[!@#$%^&*<>])+-(\\w|[!@#$%^&*<>])+") - if re.MatchString(path) { // if non local actor post - name := GetActorFollowNameFromPath(path) + if re.MatchString(postId) { // if non local actor post + name := GetActorFollowNameFromPath(postId) followActors := GetActorsFollowFromName(actor, name) - followCollection := GetActorsFollowPostFromId(db, followActors, postId) + followCollection := GetActorsFollowPostFromId(DB, followActors, postId) if len(followCollection.OrderedItems) > 0 { returnData.Board.InReplyTo = followCollection.OrderedItems[0].Id @@ -542,7 +463,7 @@ func PostGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { returnData.Board.Post.Actor = actor.Id } } else { - collection := GetObjectByIDFromDB(db, inReplyTo) + collection := GetObjectByIDFromDB(DB, inReplyTo) if collection.Actor != nil { returnData.Board.Post.Actor = collection.Actor.Id returnData.Board.InReplyTo = inReplyTo @@ -558,15 +479,12 @@ func PostGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { } returnData.Themes = &Themes - if cookie, err := r.Cookie("theme"); err == nil { - returnData.ThemeCookie = strings.SplitN(cookie.String(), "=", 2)[1] - } - err := t.ExecuteTemplate(w, "layout", returnData) - if err != nil { - // TODO: actual error handler - log.Printf("PostGet: %s\n", err) - } + returnData.ThemeCookie = GetThemeCookie(c) + + return c.Render("npost", fiber.Map{ + "page": returnData, + }, "layouts/main") } func GetBoardCollection(db *sql.DB) []Board { @@ -1147,3 +1065,13 @@ func IsOnion(url string) bool { return false } + +func GetThemeCookie(c *fiber.Ctx) string { + cookie := c.Cookies("theme") + if cookie != "" { + cookies := strings.SplitN(cookie, "=", 2) + return cookies[0] + } + + return "default" +} diff --git a/go.mod b/go.mod index 65e54be..2f46396 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,8 @@ module github.com/FChannel/Server go 1.15 require ( - github.com/gofrs/uuid v4.0.0+incompatible + github.com/gofiber/fiber/v2 v2.20.2 + github.com/gofiber/template v1.6.18 github.com/gomodule/redigo v2.0.0+incompatible github.com/lib/pq v1.9.0 github.com/simia-tech/crypt v0.5.0 diff --git a/go.sum b/go.sum index dacf5be..fe9140e 100644 --- a/go.sum +++ b/go.sum @@ -1,21 +1,619 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= +github.com/CloudyKit/jet/v6 v6.1.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= +github.com/Joker/hpp v0.0.0-20180418125244-6893e659854a/go.mod h1:MzD2WMdSxvbHw5fM/OXOFily/lipJWRc9C1px0Mt0ZE= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Joker/jade v1.0.0/go.mod h1:efZIdO0py/LtcJRSa/j2WEklMSAw84WV0zZVMxNToB8= +github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/cbroglie/mustache v1.3.0/go.mod h1:w58RIHjw/L7DPyRX2CcCTduNmcP1dvztaHP72ciSfh0= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofiber/fiber/v2 v2.20.1/go.mod h1:/LdZHMUXZvTTo7gU4+b1hclqCAdoQphNQ9bi9gutPyI= +github.com/gofiber/fiber/v2 v2.20.2 h1:dqizbjO1pCmH6K+b+kBk7TCJK4rmgjJXvX8/MZDbK60= +github.com/gofiber/fiber/v2 v2.20.2/go.mod h1:/LdZHMUXZvTTo7gU4+b1hclqCAdoQphNQ9bi9gutPyI= +github.com/gofiber/template v1.6.18 h1:nrDaRKJWS1vyuMLqijbiP+ryT2CIFYOr+jZnPmVf0Io= +github.com/gofiber/template v1.6.18/go.mod h1:HfYYaUgBhj9nMknxczh3U2LtZ88Avd1IPThD3GTUtd8= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-slim v0.0.0-20200618151855-bde33eecb5ee/go.mod h1:ma9TUJeni8LGZMJvOwbAv/FOwiwqIMQN570LnpqCBSM= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/simia-tech/crypt v0.5.0 h1:Y8xfAGqgd2wW2o4E63WIy9xr9w4jC1tDsOBHGKiqP0s= github.com/simia-tech/crypt v0.5.0/go.mod h1:DMwvjPTzsiHrjqHVW5HvIbF4vUUzMCYDKVLsPWmLdTo= -github.com/stretchr/testify v1.2.0 h1:LThGCOvhuJic9Gyd1VBCkhyUXmO8vKaBFvBsJ2k03rg= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869 h1:kkXA53yGe04D0adEYJwEVQjeBppL01Exg+fnMjfUraU= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.29.0 h1:F5GKpytwFk5OhCuRh6H+d4vZAcEeNAwPTdwQnm6IERY= +github.com/valyala/fasthttp v1.29.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/sys v0.0.0-20181116161606-93218def8b18 h1:Wh+XCfg3kNpjhdq2LXrsiOProjtQZKme5XUx7VcxwAw= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116161606-93218def8b18/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/main.go b/main.go index 4f20ad7..7e228fa 100644 --- a/main.go +++ b/main.go @@ -8,1322 +8,278 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/gofrs/uuid" - _ "github.com/lib/pq" - "html/template" - "io" - "io/ioutil" - "log" - "math/rand" - "mime/multipart" - "net/http" - "net/url" - "os" - "os/exec" - "path" - "regexp" - "strconv" - "strings" - "time" -) - -var Port = ":" + GetConfigValue("instanceport", "3000") -var TP = GetConfigValue("instancetp", "") -var Instance = GetConfigValue("instance", "") -var Domain = TP + "" + Instance -var TorInstance = IsOnion(Instance) - -var authReq = []string{"captcha", "email", "passphrase"} - -var supportedFiles = []string{"image/gif", "image/jpeg", "image/png", "image/webp", "image/apng", "video/mp4", "video/ogg", "video/webm", "audio/mpeg", "audio/ogg", "audio/wav", "audio/wave", "audio/x-wav"} - -var SiteEmail = GetConfigValue("emailaddress", "") //contact@fchan.xyz -var SiteEmailPassword = GetConfigValue("emailpass", "") -var SiteEmailServer = GetConfigValue("emailserver", "") //mail.fchan.xyz -var SiteEmailPort = GetConfigValue("emailport", "") //587 - -var TorProxy = GetConfigValue("torproxy", "") //127.0.0.1:9050 - -var PublicIndexing = strings.ToLower(GetConfigValue("publicindex", "false")) - -var Salt = GetConfigValue("instancesalt", "") - -var activitystreams = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" - -var MediaHashs = make(map[string]string) - -var ActorCache = make(map[string]Actor) - -var Themes []string - -func main() { - - CreatedNeededDirectories() - - InitCache() - - db := ConnectDB() - - defer db.Close() - - RunDatabaseSchema(db) - - go MakeCaptchas(db, 100) - - *Key = CreateKey(32) - - FollowingBoards = GetActorFollowingDB(db, Domain) - - go StartupArchive(db) - - go CheckInactive(db) - - Boards = GetBoardCollection(db) - - // root actor is used to follow remote feeds that are not local - //name, prefname, summary, auth requirements, restricted - if GetConfigValue("instancename", "") != "" { - CreateNewBoardDB(db, *CreateNewActor("", GetConfigValue("instancename", ""), GetConfigValue("instancesummary", ""), authReq, false)) - if PublicIndexing == "true" { - AddInstanceToIndex(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" { - Themes = append(Themes, strings.TrimSuffix(f.Name(), e)) - } - } - - // Allow access to public media folder - fileServer := http.FileServer(http.Dir("./public")) - http.Handle("/public/", http.StripPrefix("/public", neuter(fileServer))) - - javascriptFiles := http.FileServer(http.Dir("./static")) - http.Handle("/static/", http.StripPrefix("/static", neuter(javascriptFiles))) - - // main routing - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - path := r.URL.Path - - // remove trailing slash - if path != "/" { - re := regexp.MustCompile(`/$`) - path = re.ReplaceAllString(path, "") - } - - var mainActor bool - var mainInbox bool - var mainOutbox bool - var mainFollowing bool - var mainFollowers bool - - var actorMain bool - var actorInbox bool - var actorCatalog bool - var actorOutbox bool - var actorPost bool - var actorFollowing bool - var actorFollowers bool - var actorReported bool - var actorVerification bool - var actorMainPage bool - var actorArchive bool - - var accept = r.Header.Get("Accept") - - var method = r.Method - - var actor = GetActorFromPath(db, path, "/") - - if actor.Name == "main" { - mainActor = (path == "/") - mainInbox = (path == "/inbox") - mainOutbox = (path == "/outbox") - mainFollowing = (path == "/following") - mainFollowers = (path == "/followers") - } else { - actorMain = (path == "/"+actor.Name) - actorInbox = (path == "/"+actor.Name+"/inbox") - actorCatalog = (path == "/"+actor.Name+"/catalog") - actorOutbox = (path == "/"+actor.Name+"/outbox") - actorFollowing = (path == "/"+actor.Name+"/following") - actorFollowers = (path == "/"+actor.Name+"/followers") - actorReported = (path == "/"+actor.Name+"/reported") - actorVerification = (path == "/"+actor.Name+"/verification") - actorArchive = (path == "/"+actor.Name+"/archive") - - escapedActorName := strings.Replace(actor.Name, "*", "\\*", -1) - escapedActorName = strings.Replace(escapedActorName, "^", "\\^", -1) - escapedActorName = strings.Replace(escapedActorName, "$", "\\$", -1) - escapedActorName = strings.Replace(escapedActorName, "?", "\\?", -1) - escapedActorName = strings.Replace(escapedActorName, "+", "\\+", -1) - escapedActorName = strings.Replace(escapedActorName, ".", "\\.", -1) - - re := regexp.MustCompile("/" + escapedActorName + "/[0-9]{1,2}$") - - actorMainPage = re.MatchString(path) - - re = regexp.MustCompile("/" + escapedActorName + "/\\w+") - - actorPost = re.MatchString(path) - } - - if mainActor { - if acceptActivity(accept) { - GetActorInfo(w, db, Domain) - return - } - - IndexGet(w, r, db) - - return - } - - if mainInbox { - if method == "POST" { - - } else { - w.WriteHeader(http.StatusForbidden) - w.Write([]byte("404 no path")) - } - return - } - - if mainOutbox { - if method == "GET" { - GetActorOutbox(w, r, db) - } else if method == "POST" { - ParseOutboxRequest(w, r, db) - } else { - w.WriteHeader(http.StatusForbidden) - w.Write([]byte("404 no path")) - } - return - } - - if mainFollowing { - GetActorFollowing(w, db, Domain) - return - } - - if mainFollowers { - GetActorFollowers(w, db, Domain) - return - } - - if actorMain || actorMainPage { - if acceptActivity(accept) { - GetActorInfo(w, db, actor.Id) - return - } - - postNum := r.URL.Query().Get("page") - - page, _ := strconv.Atoi(postNum) - collection, valid := WantToServePage(db, actor.Name, page) - - if valid { - OutboxGet(w, r, db, collection) - } - - return - } - - if actorFollowing { - GetActorFollowing(w, db, actor.Id) - return - } - - if actorFollowers { - GetActorFollowers(w, db, actor.Id) - return - } - - if actorInbox { - if method == "POST" { - ParseInboxRequest(w, r, db) - } else { - w.WriteHeader(http.StatusForbidden) - w.Write([]byte("404 no path")) - } - return - } - - if actorCatalog { - collection, valid := WantToServeCatalog(db, actor.Name) - if valid { - CatalogGet(w, r, db, collection) - } - return - } - - if actorOutbox { - if method == "GET" { - GetActorOutbox(w, r, db) - } else if method == "POST" { - ParseOutboxRequest(w, r, db) - } else { - w.WriteHeader(http.StatusForbidden) - w.Write([]byte("404 no path")) - } - return - } - - if actorArchive { - collection, valid := WantToServeArchive(db, actor.Name) - if valid { - ArchiveGet(w, r, db, collection) - } - return - } - - if actorReported { - GetActorReported(w, r, db, actor.Id) - return - } - - if actorVerification { - r.ParseForm() - - code := r.FormValue("code") - - var verify Verify - - verify.Board = actor.Id - verify.Identifier = "post" - - verify = GetVerificationCode(db, verify) - - auth := CreateTripCode(verify.Code) - auth = CreateTripCode(auth) - - if CreateTripCode(auth) == code { - w.WriteHeader(http.StatusOK) - } else { - w.WriteHeader(http.StatusUnauthorized) - } - - w.Write([]byte("")) - } - - //catch all - if actorPost { - if acceptActivity(accept) { - GetActorPost(w, db, path) - return - } - - PostGet(w, r, db) - return - } - - w.WriteHeader(http.StatusForbidden) - w.Write([]byte("404 no path")) - }) - - http.HandleFunc("/news/", func(w http.ResponseWriter, r *http.Request) { - timestamp := r.URL.Path[6:] - - if len(timestamp) < 2 { - AllNewsGet(w, r, db) - return - } - - if timestamp[len(timestamp)-1:] == "/" { - timestamp = timestamp[:len(timestamp)-1] - } - - ts, err := strconv.Atoi(timestamp) - if err != nil { - w.WriteHeader(http.StatusForbidden) - w.Write([]byte("404 no path")) - } else { - NewsGet(w, r, db, ts) - } - }) - - http.HandleFunc("/post", func(w http.ResponseWriter, r *http.Request) { - - r.ParseMultipartForm(10 << 20) - - file, header, _ := r.FormFile("file") - - if IsPostBlacklist(db, r.FormValue("comment")) { - fmt.Println("\n\nBlacklist post blocked\n\n") - http.Redirect(w, r, Domain+"/", http.StatusMovedPermanently) - return - } - - if file != nil && header.Size > (7<<20) { - w.Write([]byte("7MB max file size")) - return - } - - if r.FormValue("inReplyTo") == "" && file == nil { - w.Write([]byte("Media is required for new posts")) - return - } - - if r.FormValue("inReplyTo") == "" || file == nil { - if r.FormValue("comment") == "" && r.FormValue("subject") == "" { - w.Write([]byte("Comment or Subject required")) - return - } - } - - if len(r.FormValue("comment")) > 2000 { - w.Write([]byte("Comment limit 2000 characters")) - return - } - - if len(r.FormValue("subject")) > 100 || len(r.FormValue("name")) > 100 || len(r.FormValue("options")) > 100 { - w.Write([]byte("Name, Subject or Options limit 100 characters")) - return - } - - if r.FormValue("captcha") == "" { - w.Write([]byte("Incorrect Captcha")) - return - } - - b := bytes.Buffer{} - we := multipart.NewWriter(&b) - - if file != nil { - var fw io.Writer - - fw, err := we.CreateFormFile("file", header.Filename) - - CheckError(err, "error with form file create") - - _, err = io.Copy(fw, file) - - CheckError(err, "error with form file copy") - } - - reply := ParseCommentForReply(r.FormValue("comment")) - - for key, r0 := range r.Form { - if key == "captcha" { - err := we.WriteField(key, r.FormValue("captchaCode")+":"+r.FormValue("captcha")) - CheckError(err, "error with writing captcha field") - } else if key == "name" { - name, tripcode := CreateNameTripCode(r, db) - err := we.WriteField(key, name) - CheckError(err, "error with writing name field") - err = we.WriteField("tripcode", tripcode) - CheckError(err, "error with writing tripcode field") - } else { - err := we.WriteField(key, r0[0]) - CheckError(err, "error with writing field") - } - } - - if r.FormValue("inReplyTo") == "" && reply != "" { - err := we.WriteField("inReplyTo", reply) - CheckError(err, "error with writing inReplyTo field") - } - - we.Close() - - sendTo := r.FormValue("sendTo") - req, err := http.NewRequest("POST", sendTo, &b) - - CheckError(err, "error with post form req") - - req.Header.Set("Content-Type", we.FormDataContentType()) - - resp, err := RouteProxy(req) - - CheckError(err, "error with post form resp") - - defer resp.Body.Close() - - if resp.StatusCode == 200 { - - body, _ := ioutil.ReadAll(resp.Body) - - var obj ObjectBase - - obj = ParseOptions(r, obj) - for _, e := range obj.Option { - if e == "noko" || e == "nokosage" { - http.Redirect(w, r, Domain+"/"+r.FormValue("boardName")+"/"+shortURL(r.FormValue("sendTo"), string(body)), http.StatusMovedPermanently) - return - } - } - - if r.FormValue("returnTo") == "catalog" { - http.Redirect(w, r, Domain+"/"+r.FormValue("boardName")+"/catalog", http.StatusMovedPermanently) - } else { - http.Redirect(w, r, Domain+"/"+r.FormValue("boardName"), http.StatusMovedPermanently) - } - return - } - - if resp.StatusCode == 403 { - w.Write([]byte("Incorrect Captcha")) - return - } - - http.Redirect(w, r, Domain+"/"+r.FormValue("boardName"), http.StatusMovedPermanently) - }) - - http.HandleFunc("/"+*Key+"/", func(w http.ResponseWriter, r *http.Request) { - - id, _ := GetPasswordFromSession(r) - actor := GetActorFromPath(db, r.URL.Path, "/"+*Key+"/") - - if actor.Id == "" { - actor = GetActorFromDB(db, Domain) - } - - if id == "" || (id != actor.Id && id != Domain) { - t := template.Must(template.ParseFiles("./static/verify.html")) - t.Execute(w, "") - return - } - - re := regexp.MustCompile("/" + *Key + "/" + actor.Name + "/follow") - follow := re.MatchString(r.URL.Path) - - re = regexp.MustCompile("/" + *Key + "/" + actor.Name) - manage := re.MatchString(r.URL.Path) - - re = regexp.MustCompile("/" + *Key) - admin := re.MatchString(r.URL.Path) - - re = regexp.MustCompile("/" + *Key + "/follow") - adminFollow := re.MatchString(r.URL.Path) - - if follow || adminFollow { - r.ParseForm() - - following := regexp.MustCompile(`(.+)\/following`) - followers := regexp.MustCompile(`(.+)\/followers`) - - follow := r.FormValue("follow") - actorId := r.FormValue("actor") - - //follow all of boards following - if following.MatchString(follow) { - followingActor := FingerActor(follow) - col := GetActorCollection(followingActor.Following) - - var nObj ObjectBase - nObj.Id = followingActor.Id - - col.Items = append(col.Items, nObj) - - for _, e := range col.Items { - if !IsAlreadyFollowing(db, actorId, e.Id) && e.Id != Domain && e.Id != actorId { - followActivity := MakeFollowActivity(db, actorId, e.Id) - - if FingerActor(e.Id).Id != "" { - MakeActivityRequestOutbox(db, followActivity) - } - } - } - - //follow all of boards followers - } else if followers.MatchString(follow) { - followersActor := FingerActor(follow) - col := GetActorCollection(followersActor.Followers) - - var nObj ObjectBase - nObj.Id = followersActor.Id - - col.Items = append(col.Items, nObj) - - for _, e := range col.Items { - if !IsAlreadyFollowing(db, actorId, e.Id) && e.Id != Domain && e.Id != actorId { - followActivity := MakeFollowActivity(db, actorId, e.Id) - if FingerActor(e.Id).Id != "" { - MakeActivityRequestOutbox(db, followActivity) - } - } - } - - //do a normal follow to a single board - } else { - followActivity := MakeFollowActivity(db, actorId, follow) - - if followActivity.Actor.Id == Domain && !IsActorLocal(db, followActivity.Object.Actor) { - w.Write([]byte("main board can only follow local boards. Create a new board and then follow outside boards from it.")) - return - } - - if FingerActor(follow).Id != "" { - MakeActivityRequestOutbox(db, followActivity) - } - } - - var redirect string - if actor.Name != "main" { - redirect = "/" + actor.Name - } - - http.Redirect(w, r, "/"+*Key+"/"+redirect, http.StatusSeeOther) - } else if manage && actor.Name != "" { - t := template.Must(template.New("").Funcs(template.FuncMap{ - "sub": func(i, j int) int { return i - j }}).ParseFiles("./static/main.html", "./static/manage.html")) - - follow := GetActorCollection(actor.Following) - follower := GetActorCollection(actor.Followers) - reported := GetActorCollectionReq(r, actor.Id+"/reported") - - var following []string - var followers []string - var reports []Report - - for _, e := range follow.Items { - following = append(following, e.Id) - } - - for _, e := range follower.Items { - followers = append(followers, e.Id) - } - - for _, e := range reported.Items { - var r Report - r.Count = int(e.Size) - r.ID = e.Id - r.Reason = e.Content - reports = append(reports, r) - } - - localReports := GetLocalReportDB(db, actor.Name) - - for _, e := range localReports { - var r Report - r.Count = e.Count - r.ID = e.ID - r.Reason = e.Reason - reports = append(reports, r) - } - - var adminData AdminPage - adminData.Following = following - adminData.Followers = followers - adminData.Reported = reports - adminData.Domain = Domain - adminData.IsLocal = IsActorLocal(db, actor.Id) - - adminData.Title = "Manage /" + actor.Name + "/" - adminData.Boards = Boards - adminData.Board.Name = actor.Name - adminData.Board.Actor = actor - adminData.Key = *Key - adminData.Board.TP = TP - - adminData.Board.Post.Actor = actor.Id - - adminData.AutoSubscribe = GetActorAutoSubscribeDB(db, actor.Id) - - adminData.Themes = &Themes - - if cookie, err := r.Cookie("theme"); err == nil { - adminData.ThemeCookie = strings.SplitN(cookie.String(), "=", 2)[1] - } - - err = t.ExecuteTemplate(w, "layout", adminData) - if err != nil { - // TODO: actual error handling - log.Printf("mod page: %s\n", err) - } - - } else if admin || actor.Id == Domain { - t := template.Must(template.New("").Funcs(template.FuncMap{ - "sub": func(i, j int) int { return i - j }}).ParseFiles("./static/main.html", "./static/nadmin.html")) - - actor := GetActor(Domain) - follow := GetActorCollection(actor.Following).Items - follower := GetActorCollection(actor.Followers).Items - - var following []string - var followers []string - - for _, e := range follow { - following = append(following, e.Id) - } - - for _, e := range follower { - followers = append(followers, e.Id) - } - - var adminData AdminPage - adminData.Following = following - adminData.Followers = followers - adminData.Actor = actor.Id - adminData.Key = *Key - adminData.Domain = Domain - adminData.Board.ModCred, _ = GetPasswordFromSession(r) - - adminData.Boards = Boards - - adminData.Board.Post.Actor = actor.Id - - adminData.PostBlacklist = GetRegexBlacklistDB(db) - - adminData.Themes = &Themes - if cookie, err := r.Cookie("theme"); err == nil { - adminData.ThemeCookie = strings.SplitN(cookie.String(), "=", 2)[1] - } - - err = t.ExecuteTemplate(w, "layout", adminData) - if err != nil { - // TODO: actual error handling - log.Printf("mod page: %s\n", err) - } - } - }) - - http.HandleFunc("/"+*Key+"/addboard", func(w http.ResponseWriter, r *http.Request) { - - actor := GetActorFromDB(db, Domain) - - if !HasValidation(w, r, actor) { - return - } - - var newActorActivity Activity - var board Actor - r.ParseForm() - - var restrict bool - if r.FormValue("restricted") == "True" { - restrict = true - } else { - restrict = false - } - - board.Name = r.FormValue("name") - board.PreferredUsername = r.FormValue("prefname") - board.Summary = r.FormValue("summary") - board.Restricted = restrict - - newActorActivity.AtContext.Context = "https://www.w3.org/ns/activitystreams" - newActorActivity.Type = "New" - - var nobj ObjectBase - newActorActivity.Actor = &actor - newActorActivity.Object = &nobj - - newActorActivity.Object.Alias = board.Name - newActorActivity.Object.Name = board.PreferredUsername - newActorActivity.Object.Summary = board.Summary - newActorActivity.Object.Sensitive = board.Restricted - - MakeActivityRequestOutbox(db, newActorActivity) - http.Redirect(w, r, "/"+*Key, http.StatusSeeOther) - }) - - http.HandleFunc("/"+*Key+"/postnews", func(w http.ResponseWriter, r *http.Request) { - - actor := GetActorFromDB(db, Domain) - - if !HasValidation(w, r, actor) { - return - } - - var newsitem NewsItem - - newsitem.Title = r.FormValue("title") - newsitem.Content = template.HTML(r.FormValue("summary")) - - WriteNewsToDB(db, newsitem) - - http.Redirect(w, r, "/", http.StatusSeeOther) - }) - - http.HandleFunc("/"+*Key+"/newsdelete/", func(w http.ResponseWriter, r *http.Request) { - - actor := GetActorFromDB(db, Domain) - - if !HasValidation(w, r, actor) { - return - } - - timestamp := r.URL.Path[13+len(*Key):] - - tsint, err := strconv.Atoi(timestamp) - - if err != nil { - w.WriteHeader(http.StatusForbidden) - w.Write([]byte("404 no path")) - return - } else { - deleteNewsItemFromDB(db, tsint) - http.Redirect(w, r, "/news/", http.StatusSeeOther) - } - }) - - http.HandleFunc("/verify", func(w http.ResponseWriter, r *http.Request) { - if r.Method == "POST" { - r.ParseForm() - identifier := r.FormValue("id") - code := r.FormValue("code") - - var verify Verify - verify.Identifier = identifier - verify.Code = code - - j, _ := json.Marshal(&verify) - - req, err := http.NewRequest("POST", Domain+"/auth", bytes.NewBuffer(j)) - - CheckError(err, "error making verify req") - - req.Header.Set("Content-Type", activitystreams) - - resp, err := http.DefaultClient.Do(req) - - CheckError(err, "error getting verify resp") - - defer resp.Body.Close() - - rBody, _ := ioutil.ReadAll(resp.Body) - - body := string(rBody) - - if resp.StatusCode != 200 { - t := template.Must(template.ParseFiles("./static/verify.html")) - t.Execute(w, "wrong password "+verify.Code) - } else { - - sessionToken, _ := uuid.NewV4() - - _, err := cache.Do("SETEX", sessionToken, "86400", body+"|"+verify.Code) - if err != nil { - t := template.Must(template.ParseFiles("./static/verify.html")) - t.Execute(w, "") - return - } - - http.SetCookie(w, &http.Cookie{ - Name: "session_token", - Value: sessionToken.String(), - Expires: time.Now().UTC().Add(60 * 60 * 48 * time.Second), - }) - - http.Redirect(w, r, "/", http.StatusSeeOther) - } - } else { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("404 no path")) - } - }) - - http.HandleFunc("/banmedia", func(w http.ResponseWriter, r *http.Request) { - id := r.URL.Query().Get("id") - board := r.URL.Query().Get("board") - - _, auth := GetPasswordFromSession(r) - - if id == "" || auth == "" { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } - - col := GetCollectionFromID(id) - - if len(col.OrderedItems) > 0 { - - actor := col.OrderedItems[0].Actor - - if !HasAuth(db, auth, actor) { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } - - if len(col.OrderedItems[0].Attachment) > 0 { - re := regexp.MustCompile(Domain) - file := re.ReplaceAllString(col.OrderedItems[0].Attachment[0].Href, "") - - f, err := os.Open("." + file) - CheckError(err, "could not open attachment for ban media") - - defer f.Close() - - bytes := make([]byte, 2048) - - _, err = f.Read(bytes) - if err != nil { - fmt.Println("error readin bytes for setting media ban") - } - - if !IsMediaBanned(db, f) { - query := `insert into bannedmedia (hash) values ($1)` - - _, err := db.Exec(query, HashBytes(bytes)) - - CheckError(err, "error inserting banend media into db") - - } - - var obj ObjectBase - obj.Id = id - obj.Actor = actor - - isOP := CheckIfObjectOP(db, obj.Id) - - var OP string - if len(col.OrderedItems[0].InReplyTo) > 0 { - OP = col.OrderedItems[0].InReplyTo[0].Id - } - - if !isOP { - TombstoneObject(db, id) - } else { - TombstoneObjectAndReplies(db, id) - } - - if IsIDLocal(db, id) { - go DeleteObjectRequest(db, id) - } - - UnArchiveLast(db, actor) - - if !isOP { - if !IsIDLocal(db, id) { - http.Redirect(w, r, "/"+board+"/"+remoteShort(OP), http.StatusSeeOther) - return - } else { - http.Redirect(w, r, OP, http.StatusSeeOther) - return - } - } else { - http.Redirect(w, r, "/"+board, http.StatusSeeOther) - return - } - } - } - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - }) - - http.HandleFunc("/delete", func(w http.ResponseWriter, r *http.Request) { - id := r.URL.Query().Get("id") - board := r.URL.Query().Get("board") - _, auth := GetPasswordFromSession(r) + "github.com/gofiber/fiber/v2" + "github.com/gofiber/template/html" + // "github.com/gofrs/uuid" + _ "github.com/lib/pq" - if id == "" || auth == "" { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } + "html/template" + // "io" + "io/ioutil" + // "log" + "math/rand" + "mime/multipart" + "net/http" + "net/url" + "os" + "os/exec" + "path" + "regexp" + "strconv" + "strings" + "time" +) - manage := r.URL.Query().Get("manage") - col := GetCollectionFromID(id) - if len(col.OrderedItems) < 1 { - actor := GetActorByNameFromDB(db, board) - if !HasAuth(db, auth, actor.Id) { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } +var Port = ":" + GetConfigValue("instanceport", "3000") +var TP = GetConfigValue("instancetp", "") +var Instance = GetConfigValue("instance", "") +var Domain = TP + "" + Instance +var TorInstance = IsOnion(Instance) - if !CheckIfObjectOP(db, id) { - TombstoneObject(db, id) - } else { - TombstoneObjectAndReplies(db, id) - } +var authReq = []string{"captcha", "email", "passphrase"} - UnArchiveLast(db, actor.Id) +var supportedFiles = []string{"image/gif", "image/jpeg", "image/png", "image/webp", "image/apng", "video/mp4", "video/ogg", "video/webm", "audio/mpeg", "audio/ogg", "audio/wav", "audio/wave", "audio/x-wav"} - if manage == "t" { - http.Redirect(w, r, "/"+*Key+"/"+board, http.StatusSeeOther) - return - } else { - http.Redirect(w, r, "/"+board, http.StatusSeeOther) - return - } - } +var SiteEmail = GetConfigValue("emailaddress", "") //contact@fchan.xyz +var SiteEmailPassword = GetConfigValue("emailpass", "") +var SiteEmailServer = GetConfigValue("emailserver", "") //mail.fchan.xyz +var SiteEmailPort = GetConfigValue("emailport", "") //587 - actor := col.OrderedItems[0].Actor +var TorProxy = GetConfigValue("torproxy", "") //127.0.0.1:9050 - if !HasAuth(db, auth, actor) { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } +var PublicIndexing = strings.ToLower(GetConfigValue("publicindex", "false")) - var obj ObjectBase - obj.Id = id - obj.Actor = actor +var Salt = GetConfigValue("instancesalt", "") - isOP := CheckIfObjectOP(db, obj.Id) +var activitystreams = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" - var OP string - if len(col.OrderedItems[0].InReplyTo) > 0 { - OP = col.OrderedItems[0].InReplyTo[0].Id - } +var MediaHashs = make(map[string]string) - if !isOP { - TombstoneObject(db, id) - } else { - TombstoneObjectAndReplies(db, id) - } +var ActorCache = make(map[string]Actor) - if IsIDLocal(db, id) { - go DeleteObjectRequest(db, id) - } +var Themes []string - UnArchiveLast(db, actor) +var DB *sql.DB - if manage == "t" { - http.Redirect(w, r, "/"+*Key+"/"+board, http.StatusSeeOther) - return - } else if !isOP { - if !IsIDLocal(db, id) { - http.Redirect(w, r, "/"+board+"/"+remoteShort(OP), http.StatusSeeOther) - return - } else { - http.Redirect(w, r, OP, http.StatusSeeOther) - return - } - } else { - http.Redirect(w, r, "/"+board, http.StatusSeeOther) - return - } - }) +func main() { - http.HandleFunc("/deleteattach", func(w http.ResponseWriter, r *http.Request) { + CreatedNeededDirectories() - id := r.URL.Query().Get("id") - board := r.URL.Query().Get("board") + InitCache() - _, auth := GetPasswordFromSession(r) + DB = ConnectDB() - if id == "" || auth == "" { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } + defer DB.Close() - manage := r.URL.Query().Get("manage") - col := GetCollectionFromID(id) + RunDatabaseSchema(DB) - if len(col.OrderedItems) < 1 { - if !HasAuth(db, auth, GetActorByNameFromDB(db, board).Id) { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } + go MakeCaptchas(DB, 100) - DeleteAttachmentFromFile(db, id) - TombstoneAttachmentFromDB(db, id) + *Key = CreateKey(32) - DeletePreviewFromFile(db, id) - TombstonePreviewFromDB(db, id) + FollowingBoards = GetActorFollowingDB(DB, Domain) - if manage == "t" { - http.Redirect(w, r, "/"+*Key+"/"+board, http.StatusSeeOther) - return - } else { - http.Redirect(w, r, "/"+board, http.StatusSeeOther) - return - } - } + go StartupArchive(DB) - actor := col.OrderedItems[0].Actor + go CheckInactive(DB) - var OP string - if len(col.OrderedItems[0].InReplyTo) > 0 && col.OrderedItems[0].InReplyTo[0].Id != "" { - OP = col.OrderedItems[0].InReplyTo[0].Id - } else { - OP = id - } + Boards = GetBoardCollection(DB) - if !HasAuth(db, auth, actor) { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return + // root actor is used to follow remote feeds that are not local + //name, prefname, summary, auth requirements, restricted + if GetConfigValue("instancename", "") != "" { + CreateNewBoardDB(DB, *CreateNewActor("", GetConfigValue("instancename", ""), GetConfigValue("instancesummary", ""), authReq, false)) + if PublicIndexing == "true" { + AddInstanceToIndex(Domain) } + } - DeleteAttachmentFromFile(db, id) - TombstoneAttachmentFromDB(db, id) - - DeletePreviewFromFile(db, id) - TombstonePreviewFromDB(db, id) + // get list of themes + themes, err := ioutil.ReadDir("./static/css/themes") + if err != nil { + panic(err) + } - if manage == "t" { - http.Redirect(w, r, "/"+*Key+"/"+board, http.StatusSeeOther) - return - } else if !IsIDLocal(db, OP) { - http.Redirect(w, r, "/"+board+"/"+remoteShort(OP), http.StatusSeeOther) - return - } else { - http.Redirect(w, r, OP, http.StatusSeeOther) - return + for _, f := range themes { + if e := path.Ext(f.Name()); e == ".css" { + Themes = append(Themes, strings.TrimSuffix(f.Name(), e)) } - }) - - http.HandleFunc("/marksensitive", func(w http.ResponseWriter, r *http.Request) { - - id := r.URL.Query().Get("id") - board := r.URL.Query().Get("board") - - _, auth := GetPasswordFromSession(r) + } - if id == "" || auth == "" { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } + // Allow access to public media folder + fileServer := http.FileServer(http.Dir("./public")) + http.Handle("/public/", http.StripPrefix("/public", neuter(fileServer))) - col := GetCollectionFromID(id) + javascriptFiles := http.FileServer(http.Dir("./static")) + http.Handle("/static/", http.StripPrefix("/static", neuter(javascriptFiles))) - if len(col.OrderedItems) < 1 { - if !HasAuth(db, auth, GetActorByNameFromDB(db, board).Id) { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } + /* Routing and templates */ - MarkObjectSensitive(db, id, true) + template := html.New("./views", ".html") - http.Redirect(w, r, "/"+board, http.StatusSeeOther) - return - } + TemplateFunctions(template) - actor := col.OrderedItems[0].Actor + app := fiber.New(fiber.Config{ + Views: template, + }) - var OP string - if len(col.OrderedItems[0].InReplyTo) > 0 && col.OrderedItems[0].InReplyTo[0].Id != "" { - OP = col.OrderedItems[0].InReplyTo[0].Id - } else { - OP = id - } + app.Static("/public", "./public") + app.Static("/static", "./views") - if !HasAuth(db, auth, actor) { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } + /* + Main actor + */ - MarkObjectSensitive(db, id, true) + app.Get("/", IndexGet) - if !IsIDLocal(db, OP) { - http.Redirect(w, r, "/"+board+"/"+remoteShort(OP), http.StatusSeeOther) - return - } else { - http.Redirect(w, r, OP, http.StatusSeeOther) - return - } + app.Get("/inbox", func(c *fiber.Ctx) error { + return c.SendString("main inbox") }) - http.HandleFunc("/remove", func(w http.ResponseWriter, r *http.Request) { - id := r.URL.Query().Get("id") - manage := r.URL.Query().Get("manage") - board := r.URL.Query().Get("board") - col := GetCollectionFromID(id) - actor := col.OrderedItems[0].Actor - _, auth := GetPasswordFromSession(r) - - if id == "" || auth == "" { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } + app.Get("/outbox", func(c *fiber.Ctx) error { + return c.SendString("main outbox") + }) - if !HasAuth(db, auth, actor) { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } + app.Get("/following", func(c *fiber.Ctx) error { + return c.SendString("main following") + }) - var obj ObjectBase - obj.Id = id - obj.Actor = actor + app.Get("/followers", func(c *fiber.Ctx) error { + return c.SendString("main followers") + }) - isOP := CheckIfObjectOP(db, obj.Id) + /* + Board actor + */ - var OP string - if len(col.OrderedItems[0].InReplyTo) > 0 { - OP = col.OrderedItems[0].InReplyTo[0].Id - } + app.Get("/:actor", OutboxGet) - if !isOP { - SetObject(db, id, "Removed") - } else { - SetObjectAndReplies(db, id, "Removed") - } + app.Get("/:actor/:post", PostGet) - if manage == "t" { - http.Redirect(w, r, "/"+*Key+"/"+board, http.StatusSeeOther) - return - } else if !isOP { - if !IsIDLocal(db, id) { - http.Redirect(w, r, "/"+board+"/"+remoteShort(OP), http.StatusSeeOther) - return - } else { - http.Redirect(w, r, OP, http.StatusSeeOther) - return - } - } else { - http.Redirect(w, r, "/"+board, http.StatusSeeOther) - return - } + app.Get("/:actor/inbox", func(c *fiber.Ctx) error { + return c.SendString("actor inbox") }) - http.HandleFunc("/removeattach", func(w http.ResponseWriter, r *http.Request) { - - id := r.URL.Query().Get("id") - manage := r.URL.Query().Get("manage") - board := r.URL.Query().Get("board") - col := GetCollectionFromID(id) - actor := col.OrderedItems[0].Actor - - var OP string - if len(col.OrderedItems[0].InReplyTo) > 0 && col.OrderedItems[0].InReplyTo[0].Id != "" { - OP = col.OrderedItems[0].InReplyTo[0].Id - } else { - OP = id - } - - _, auth := GetPasswordFromSession(r) + app.Get("/:actor/outbox", func(c *fiber.Ctx) error { + return c.SendString("actor outbox") + }) - if id == "" || auth == "" { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } + app.Get("/:actor/following", func(c *fiber.Ctx) error { + return c.SendString("actor following") + }) - if !HasAuth(db, auth, actor) { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } + app.Get("/:actor/followers", func(c *fiber.Ctx) error { + return c.SendString("actor followers") + }) - SetAttachmentFromDB(db, id, "Removed") - SetPreviewFromDB(db, id, "Removed") + app.Get("/:actor/reported", func(c *fiber.Ctx) error { + return c.SendString("actor reported") + }) - if manage == "t" { - http.Redirect(w, r, "/"+*Key+"/"+board, http.StatusSeeOther) - return - } else if !IsIDLocal(db, OP) { - http.Redirect(w, r, "/"+board+"/"+remoteShort(OP), http.StatusSeeOther) - return - } else { - http.Redirect(w, r, OP, http.StatusSeeOther) - return - } + app.Get("/:actor/archive", func(c *fiber.Ctx) error { + return c.SendString("actor archive") }) - http.HandleFunc("/report", func(w http.ResponseWriter, r *http.Request) { + app.Get("/post", func(c *fiber.Ctx) error { + return c.SendString("actor post") + }) - r.ParseForm() + /* + Admin routes + */ - id := r.FormValue("id") - board := r.FormValue("board") - reason := r.FormValue("comment") - close := r.FormValue("close") + app.Get("/verify", func(c *fiber.Ctx) error { + return c.SendString("admin verify") + }) - actor := GetActorFromPath(db, id, "/") - _, auth := GetPasswordFromSession(r) + app.Get("/auth", func(c *fiber.Ctx) error { + return c.SendString("admin auth") + }) - var captcha = r.FormValue("captchaCode") + ":" + r.FormValue("captcha") + app.Get("/"+*Key+"/", func(c *fiber.Ctx) error { + return c.SendString("admin key") + }) - if len(reason) > 100 { - w.Write([]byte("Report comment limit 100 characters")) - return - } + app.Get("/"+*Key+"/addboard", func(c *fiber.Ctx) error { + return c.SendString("admin addboard ") + }) - if close != "1" && !CheckCaptcha(db, captcha) { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("captcha required")) - return - } + app.Get("/"+*Key+"/postnews", func(c *fiber.Ctx) error { + return c.SendString("admin post news") + }) - if close == "1" { - if !HasAuth(db, auth, actor.Id) { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } + app.Get("/"+*Key+"/newsdelete", func(c *fiber.Ctx) error { + return c.SendString("admin news delete") + }) - if !IsIDLocal(db, id) { - CloseLocalReportDB(db, id, board) - http.Redirect(w, r, "/"+*Key+"/"+board, http.StatusSeeOther) - return - } + app.Get("/news", func(c *fiber.Ctx) error { + return c.SendString("admin news") + }) - reported := DeleteReportActivity(db, id) - if reported { - http.Redirect(w, r, "/"+*Key+"/"+board, http.StatusSeeOther) - return - } + /* + Board managment + */ - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) - return - } + app.Get("/banmedia", func(c *fiber.Ctx) error { + return c.SendString("board ban media") + }) - if !IsIDLocal(db, id) { - CreateLocalReportDB(db, id, board, reason) - http.Redirect(w, r, "/"+board+"/"+remoteShort(id), http.StatusSeeOther) - return - } + app.Get("/delete", func(c *fiber.Ctx) error { + return c.SendString("board delete") + }) - reported := ReportActivity(db, id, reason) - if reported { - http.Redirect(w, r, id, http.StatusSeeOther) - return - } + app.Get("/deleteattach", func(c *fiber.Ctx) error { + return c.SendString("board delete attach") + }) - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) + app.Get("/marksensitive", func(c *fiber.Ctx) error { + return c.SendString("board mark sensitive") }) - http.HandleFunc("/auth", func(w http.ResponseWriter, r *http.Request) { - var verify Verify - defer r.Body.Close() + app.Get("/remove", func(c *fiber.Ctx) error { + return c.SendString("board remove") + }) - body, _ := ioutil.ReadAll(r.Body) + app.Get("/removeattach", func(c *fiber.Ctx) error { + return c.SendString("Hello World") + }) - err := json.Unmarshal(body, &verify) + app.Get("/addtoindex", func(c *fiber.Ctx) error { + return c.SendString("board add to index") + }) - CheckError(err, "error get verify from json") + app.Get("/poparchive", func(c *fiber.Ctx) error { + return c.SendString("board pop archive") + }) - v := GetVerificationByCode(db, verify.Code) + app.Get("/autosubscribe", func(c *fiber.Ctx) error { + return c.SendString("board autosubscribe") + }) - if v.Identifier == verify.Identifier { - w.Write([]byte(v.Board)) - return - } + app.Get("/blacklist", func(c *fiber.Ctx) error { + return c.SendString("board blacklist") + }) - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) + app.Get("/report", func(c *fiber.Ctx) error { + return c.SendString("board report") }) - http.HandleFunc("/.well-known/webfinger", func(w http.ResponseWriter, r *http.Request) { - acct := r.URL.Query()["resource"] + app.Get("/.well-known/webfinger", func(c *fiber.Ctx) error { + acct := c.Query("resource") if len(acct) < 1 { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("resource needs a value")) - return + c.Status(fiber.StatusBadRequest) + return c.Send([]byte("resource needs a value")) } - acct[0] = strings.Replace(acct[0], "acct:", "", -1) + acct = strings.Replace(acct, "acct:", "", -1) - actorDomain := strings.Split(acct[0], "@") + actorDomain := strings.Split(acct, "@") if len(actorDomain) < 2 { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("accpets only subject form of acct:board@instance")) - return + c.Status(fiber.StatusBadRequest) + return c.Send([]byte("accpets only subject form of acct:board@instance")) } if actorDomain[0] == "main" { @@ -1332,10 +288,9 @@ func main() { actorDomain[0] = "/" + actorDomain[0] } - if !IsActorLocal(db, TP+""+actorDomain[1]+""+actorDomain[0]) { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("actor not local")) - return + if !IsActorLocal(DB, TP+""+actorDomain[1]+""+actorDomain[0]) { + c.Status(fiber.StatusBadRequest) + return c.Send([]byte("actor not local")) } var finger Webfinger @@ -1350,107 +305,20 @@ func main() { enc, _ := json.Marshal(finger) - w.Header().Set("Content-Type", activitystreams) - w.Write(enc) - - }) - - http.HandleFunc("/addtoindex", func(w http.ResponseWriter, r *http.Request) { - actor := r.URL.Query().Get("id") - - if Domain != "https://fchan.xyz" { - return - } - - go AddInstanceToIndexDB(db, actor) - }) - - http.HandleFunc("/poparchive", func(w http.ResponseWriter, r *http.Request) { - - actor := GetActorFromDB(db, Domain) - - if !HasValidation(w, r, actor) { - return - } - - id := r.URL.Query().Get("id") - board := r.URL.Query().Get("board") - - SetObjectType(db, id, "Note") - - http.Redirect(w, r, "/"+board+"/archive", http.StatusSeeOther) - }) - - http.HandleFunc("/blacklist", func(w http.ResponseWriter, r *http.Request) { - - actor := GetActorFromDB(db, Domain) - - if !HasValidation(w, r, actor) { - return - } - - if r.Method == "GET" { - id := r.URL.Query().Get("remove") - - if id != "" { - i, _ := strconv.Atoi(id) - DeleteRegexBlacklistDB(db, i) - } - - } else { - regex := r.FormValue("regex") - testCase := r.FormValue("testCase") - - if regex == "" { - http.Redirect(w, r, "/", http.StatusSeeOther) - return - } - - r.ParseForm() - - re := regexp.MustCompile(regex) - - if testCase == "" { - WriteRegexBlacklistDB(db, regex) - } else if re.MatchString(testCase) { - WriteRegexBlacklistDB(db, regex) - } - } - - http.Redirect(w, r, "/"+*Key+"#regex", http.StatusSeeOther) + c.Set("Content-Type", activitystreams) + return c.Send(enc) }) - http.HandleFunc("/api/media", func(w http.ResponseWriter, r *http.Request) { - if r.URL.Query().Get("hash") != "" { - RouteImages(w, r.URL.Query().Get("hash")) - } - }) - - http.HandleFunc("/autosubscribe", func(w http.ResponseWriter, r *http.Request) { - - if !HasValidation(w, r, GetActorFromDB(db, Domain)) { - return - } - - board := r.URL.Query().Get("board") - actor := GetActorByNameFromDB(db, board) - - SetActorAutoSubscribeDB(db, actor.Id) - autoSub := GetActorAutoSubscribeDB(db, actor.Id) - - if autoSub { - AutoFollow(db, actor.Id) - } - - http.Redirect(w, r, "/"+*Key+"/"+board, http.StatusSeeOther) + app.Get("/api/media", func(c *fiber.Ctx) error { + return c.SendString("api media") }) fmt.Println("Server for " + Domain + " running on port " + Port) fmt.Println("Mod key: " + *Key) - PrintAdminAuth(db) + PrintAdminAuth(DB) - http.ListenAndServe(Port, nil) + app.Listen(Port) } func CheckError(e error, m string) error { @@ -3002,3 +1870,68 @@ func CheckInactiveInstances(db *sql.DB) map[string]string { return instances } + +func TemplateFunctions(engine *html.Engine) { + engine.AddFunc( + "mod", mod, + ) + + engine.AddFunc( + "sub", sub, + ) + + engine.AddFunc( + "unixtoreadable", unixToReadable, + ) + + engine.AddFunc("proxy", func(url string) string { + return MediaProxy(url) + }) + + engine.AddFunc("short", func(actorName string, url string) string { + return shortURL(actorName, url) + }) + + engine.AddFunc("parseAttachment", func(obj ObjectBase, catalog bool) template.HTML { + return ParseAttachment(obj, catalog) + }) + + engine.AddFunc("parseContent", func(board Actor, op string, content string, thread ObjectBase) template.HTML { + return ParseContent(DB, board, op, content, thread) + }) + + engine.AddFunc("shortImg", func(url string) string { + return ShortImg(url) + }) + + engine.AddFunc("convertSize", func(size int64) string { + return ConvertSize(size) + }) + + engine.AddFunc("isOnion", func(url string) bool { + return IsOnion(url) + }) + + engine.AddFunc("parseReplyLink", func(actorId string, op string, id string, content string) template.HTML { + actor := FingerActor(actorId) + title := strings.ReplaceAll(ParseLinkTitle(actor.Id, op, content), `/\<`, ">") + link := ">>" + shortURL(actor.Outbox, id) + "" + return template.HTML(link) + }) + + engine.AddFunc("add", func(i, j int) int { + return i + j + }) + + engine.AddFunc( + "timeToReadableLong", timeToReadableLong, + ) + + engine.AddFunc( + "timeToUnix", timeToUnix, + ) + + engine.AddFunc( + "sub", sub, + ) +} diff --git a/session.go b/session.go index 99ab1c2..b2af357 100644 --- a/session.go +++ b/session.go @@ -3,6 +3,7 @@ package main import ( "bufio" "fmt" + "github.com/gofiber/fiber/v2" "github.com/gomodule/redigo/redis" "net/http" "os" @@ -91,3 +92,26 @@ func GetPasswordFromSession(r *http.Request) (string, string) { return "", "" } + +func GetPasswordFromCtx(r *fiber.Ctx) (string, string) { + + c := r.Cookies("session_token") + + sessionToken := c + + response, err := cache.Do("GET", sessionToken) + + if CheckError(err, "could not get session from cache") != nil { + return "", "" + } + + token := fmt.Sprintf("%s", response) + + parts := strings.Split(token, "|") + + if len(parts) > 1 { + return parts[0], parts[1] + } + + return "", "" +} diff --git a/views/css/themes/default.css b/views/css/themes/default.css new file mode 100644 index 0000000..98edc29 --- /dev/null +++ b/views/css/themes/default.css @@ -0,0 +1,249 @@ +a, a:link, a:visited, a:hover, a:active { + text-decoration: none +} + +a:link, a:visited, a:active { + color: black; +} + +a:hover { + color: #de0808; +} + +body { + background-color: #eef2fe; + color: black; +} + +body.nsfw { + background-color: #ffffee; + color: #820404 +} + +h1, h2, h3, h4, h5, h6 { + color: #af0a0f; +} + +.popup-box { + border: 4px solid #d3caf0; + background-color: #eff5ff; +} + +.nsfw .popup-box { + border: 4px solid #f0e2d9; + background-color: #f9f9e0; +} + +.box { + background-color: #eff5ff; +} + +.nsfw .box { + background-color: #f9f9e0; +} + +.box-alt { + background-color: #d3caf0; +} + +.nsfw .box-alt { + background-color: #f0e2d9; +} + + +.quote { + color: #789922; +} + +.post { + background-color: #d5daf0; +} + +.nsfw .post { + background-color: #f0e0d6; +} + +:target > div > .post { + background-color: #d6bad0; +} + +.nsfw :target > div > .post { + background-color: #f0c0b0; +} + +.title { + color: #0f0c5d; +} + +.name, .tripcode { + color: #117743; +} + +a.reply { + color: #af0a0f; + text-decoration: 1px underline; +} + +.replyLink { + color: #000080; + font-size: 0.8em; +} + +#newpostbtn { + text-align: center; + margin-top: 80px; +} + +#postForm { + margin: auto; +} + +#postForm tr > td:first-child { + background-color: #98e; + border: 1px black; + padding-left: 0.5em; + padding-right: 0.5em; +} + +.nsfw #postForm tr > td:first-child { + background-color: #ea8; +} + +#postForm input[type="text"], +#postForm textarea, +#reply-name, #reply-options, #reply-comment { + box-sizing: border-box; + -webkit-box-sizing:border-box; + -moz-box-sizing: border-box; +} + +#postForm input[type="text"], +#postForm textarea, +#reply-name, #reply-options, #reply-comment { + box-sizing: border-box; + -webkit-box-sizing:border-box; + -moz-box-sizing: border-box; +} + +#reply-comment { + min-width: 300px; + width: 396px; + height: 200px; +} + +#reply-name { + width: 75%; + float: left; +} + +#reply-options { + width: 25%; + float: right; +} + +#reply-header { + display: inline-block; + width: 100%; + cursor: move; +} + +#postForm #captcha { + display: block; + width: 100%; +} + +.popup-box { + position: fixed; + min-width: 300px; + width: min-content; + z-index: 9; + display: block; +} + +/* TODO: rename */ +.box2 { + border: 4px solid #f0e2d9; + background-color: #f9f9e0; +} + +.newsbox { + padding: 25px; + border: 4px solid #f0e2d9; + background-color: #f9f9e0; +} + +.newsbox h2 { + margin: 0; + padding: 0; +} + +.newsbox-news { + text-align: left; + margin-top: 25px; + padding: 25px; +} + +.newsbox-news p, +.newsbox-news h3 { + margin: 0; +} + +#stopTablePost { + float: right; + display: none; +} + +#boardGrid { + display: grid; + grid-auto-columns: 1fr; + border: 4px solid #820404; + background-color: #f9f9e0; +} + +#boardGridHeader { + border-bottom: 2px solid #820404; + display: inline-grid; +} + +.boardGridCell { + white-space: nowrap; + display: inline-grid; + text-align: left; + padding: 5px; + border-top: 2px solid #820404; + border-left: 2px solid #820404; +} + +/* these may or may not work. my CSS is poor so i just kinda did stuff until it worked. */ +.boardGridCell:nth-child(-n+4) { + border-top: none; +} + +.boardGridCell:nth-child(3n+2) { + border-left: none; +} + +#threadfooter { + width: 100%; + table-layout: fixed; + border-collapse: collapse; +} + +#threadfooter td { + padding: 0; + margin: 0; +} + +#threadfooter #threadStats { + float: right; +} + +#navlinks, #boardlinks { + padding: 0; + margin: 0; +} + +#navlinks > li, +#boardlinks > li { + display: inline; +} diff --git a/views/css/themes/gruvbox.css b/views/css/themes/gruvbox.css new file mode 100644 index 0000000..8704482 --- /dev/null +++ b/views/css/themes/gruvbox.css @@ -0,0 +1,235 @@ +a, a:link, a:visited, a:active { + color: #b16286; + text-decoration: none +} + +a.reply { + color: #cc241d; + text-decoration: 1px underline; +} + +a:hover.reply { + color: #fb4934; +} + +body { + background: #282828; + color: #ebdbb2; + + font-family: monospace, sans-serif; + font-size: 0.9em; +} + +.popup-box { + border: 4px solid #928374; + background-color: #3c3836; +} + +.box, .box-alt { + background-color: #3c3836; +} + +.quote { + color: #98971a; +} + +.post { + background-color: #1d2021; +} + +:target > div > .post { + background-color: #504945; +} + +.subject { + color: #458588; +} + +.name { + color: #b8bb26; +} + +.tripcode { + color: #689d6a; +} + +h1,h2,h3,h4,h5,h6 { + color: #fb4934; + margin-bottom: 0.1em; +} + +.replyLink { + color: #83a598; + font-size: 0.8em; +} + +#newpostbtn { + text-align: center; + margin-top: 80px; +} + +input[type="text"] { + -webkit-appearance: none; + -webkit-border-radius: 0; +} + +#postForm { + border: 4px solid #928374; + background-color: #3c3836; + margin: auto; +} + +#postForm tr > td:first-child { + background-color: #504945; + padding-left: 0.5em; + padding-right: 0.5em; +} + +#postForm input[type="text"], +#postForm textarea, +#reply-name, #reply-options, #reply-comment { + background-color: #504945; + color: #ebdbb2; + border: 0; + border-bottom: 2px solid #3c3836; + font-family: monospace, sans-serif; + + box-sizing: border-box; + -webkit-box-sizing:border-box; + -moz-box-sizing: border-box; +} + +#postForm input[type="text"]:focus, +#postForm textarea:focus, +#reply-name:focus, #reply-options:focus, #reply-comment:focus { + outline: none; +} + +#reply-comment { + min-width: 300px; + width: 396px; + height: 200px; +} + +#reply-name { + width: 75%; + float: left; +} + +#reply-options { + width: 25%; + border-left: 2px solid #3c3836; + float: right; +} + +#reply-header { + display: inline-block; + width: 100%; + cursor: move; +} + +#postForm #captcha { + display: block; + width: 100%; +} + +.popup-box { + position: fixed; + min-width: 300px; + width: min-content; + z-index: 9; + display: block; +} + +/* TODO: rename */ +.box2 { + border: 4px solid #928374; + background-color: #3c3836; +} + +.newsbox { + padding: 25px; + border: 4px solid #928374; + background-color: #3c3836; +} + +.newsbox h2 { + margin: 0; + padding: 0; +} + +.newsbox-news { + text-align: left; + background-color: #504945; + margin-top: 25px; + padding: 25px; +} + +.newsbox-news p, +.newsbox-news h3 { + margin: 0; +} + +#stopTablePost { + float: right; + display: none; +} + +#boardGrid { + display: grid; + grid-auto-columns: 1fr; + border: 4px solid #928374; + background-color: #3c3836; +} + +#boardGridHeader { + border-bottom: 2px solid #928374; + display: inline-grid; +} + +.boardGridCell { + white-space: nowrap; + display: inline-grid; + text-align: left; + padding: 5px; + border-top: 2px solid #928374; + border-left: 2px solid #928374; +} + +/* these may or may not work. my CSS is poor so i just kinda did stuff until it worked. */ +.boardGridCell:nth-child(-n+4) { + border-top: none; +} + +.boardGridCell:nth-child(3n+2) { + border-left: none; +} + +#threadfooter { + width: 100%; + table-layout: fixed; + border-collapse: collapse; +} + +#threadfooter td { + padding: 0; + margin: 0; +} + +#threadfooter #threadStats { + float: right; +} + +#navlinks, #boardlinks { + padding: 0; + margin: 0; +} + +#navlinks > li, +#boardlinks > li { + display: inline; +} + +hr { + border: 1px solid #928374; +} diff --git a/views/index.html b/views/index.html new file mode 100644 index 0000000..f426d5d --- /dev/null +++ b/views/index.html @@ -0,0 +1,53 @@ +
{{ .page.PreferredUsername }} is a federated image board based on ActivityPub. The current version of the code running on the server is still a work-in-progress product, expect a bumpy ride for the time being. Get the server code here: https://github.com/FChannel0.
+ + {{ if .page.Boards }} + {{ $l := len .page.Boards }} +{{$e.Content}}
+{{ .Id }} | +
+ | + + {{ if eq (index .page.Posts 0).Type "Note" }} + ++ [ + ] | + {{ end }} + ++ {{ $replies := (index .page.Posts 0).Replies }} + {{ $replies.TotalItems }} / {{ $replies.TotalImgs }} + | +
All trademarks and copyrights on this page are owned by their respective parties.
+{{ parseContent $board.Actor $opId .Content $thread }}
+ {{ if .Replies }} + {{ $replies := .Replies }} + {{ if gt $replies.TotalItems 5 }} + {{ if gt $len 1 }} + {{ $replies.TotalItems }} replies{{ if gt $replies.TotalImgs 0}} and {{ $replies.TotalImgs }} images{{ end }}, Click here to view all. + {{ end }} + {{ end }} + {{ range $replies.OrderedItems }} +{{ parseContent $board.Actor $opId .Content $thread }}
+{{ .Board.Summary }}
+ {{ $len := len .Posts }} + {{ if eq $len 0 }} + {{ if .Board.InReplyTo }} +