diff --git a/.gitea/ISSUE_TEMPLATE/bug_report.md b/.gitea/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..742ebc5 --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,46 @@ +--- +name: Bug report +about: Create a bug report to help us improve Invidious +title: "[Bug] " +labels: bug +assignees: "" +--- + + + +### Describe the bug + + + +### Steps to Reproduce + + + +### Logs + + + +### Screenshots + + + +### Additional context + + diff --git a/.gitea/ISSUE_TEMPLATE/enhancement.md b/.gitea/ISSUE_TEMPLATE/enhancement.md new file mode 100644 index 0000000..9c6bcbf --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/enhancement.md @@ -0,0 +1,27 @@ +--- +name: Enhancement +about: Suggest an enhancement for an existing feature +title: "[Enhancement] " +labels: enhancement +assignees: "" +--- + + + + + +### Is your enhancement request related to a problem? Please describe. + + + +### Describe the solution you'd like + + + +### Describe alternatives you've considered + + + +### Additional context + + diff --git a/.gitea/ISSUE_TEMPLATE/feature_request.md b/.gitea/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..035f2d6 --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,27 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[Feature request] " +labels: feature +assignees: "" +--- + + + + + +### Is your feature request related to a problem? Please describe. + + + +### Describe the solution you'd like + + + +### Describe alternatives you've considered + + + +### Additional context + + diff --git a/.gitea/ISSUE_TEMPLATE/instance.yml b/.gitea/ISSUE_TEMPLATE/instance.yml index a96f3a6..60cf08d 100644 --- a/.gitea/ISSUE_TEMPLATE/instance.yml +++ b/.gitea/ISSUE_TEMPLATE/instance.yml @@ -48,4 +48,9 @@ body: label: Contact details description: Input your contact information should we need to contact you privately. We recommend Matrix. If you don't have a contact method, or don't want your contact method public, tell us. placeholder: "@foo:example.org" - \ No newline at end of file + - type: checkboxes + attributes: + label: Instance Rules + description: I have read and accepted the [instance rules](https://codeberg.org/gothub/gothub#instance-rules) + options: + - label: I have read and accepted the instance rules diff --git a/Dockerfile b/Dockerfile index 5321429..6fc8ccd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,7 @@ ARG TARGETARCH WORKDIR /src RUN apk --no-cache add git RUN git clone https://codeberg.org/gothub/gothub . +RUN git checkout master RUN go mod download RUN GOOS=linux GOARCH=$TARGETARCH go build -o /src/gothub -ldflags="-X codeberg.org/gothub/gothub/utils.Branch=master" diff --git a/DockerfileDev b/DockerfileDev index 4ac8748..fec2469 100644 --- a/DockerfileDev +++ b/DockerfileDev @@ -5,6 +5,7 @@ ARG TARGETARCH WORKDIR /src RUN apk --no-cache add git RUN git clone https://codeberg.org/gothub/gothub . +RUN git checkout dev RUN go mod download RUN GOOS=linux GOARCH=$TARGETARCH go build -o /src/gothub -ldflags="-X codeberg.org/gothub/gothub/utils.Branch=dev" diff --git a/README.md b/README.md index cf3ab0f..58d7c9e 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,15 @@ # GotHub +**GotHub is looking for new maintainers. If you are interested, please checkout [#131](https://codeberg.org/gothub/gothub/issues/131).** + Alternative front-end for GitHub written with Go. (WIP) -[Matrix](https://matrix.to/#/#gothub:matrix.org) +[![Matrix](https://img.shields.io/matrix/gothub:matrix.org?label=Matrix)](https://matrix.to/#/#gothub:matrix.org) [![Go Report Card](https://goreportcard.com/badge/codeberg.org/gothub/gothub)](https://goreportcard.com/report/codeberg.org/gothub/gothub) [![Website](https://img.shields.io/website?down_color=red&down_message=offline&up_color=green&up_message=online&url=https%3A%2F%2Fgothub.app)](https://gothub.app) ## Features + - Lightweight - for both you and the instance host - No JavaScript - pure HTML and CSS goodness - No requests made to GitHub from the client side - they won't even know you made a request! @@ -17,45 +20,62 @@ Alternative front-end for GitHub written with Go. (WIP) Tested with PageSpeed Insights. Using ansible/ansible as a test repo. -| | [GotHub](https://pagespeed.web.dev/analysis/https-gh-dev-odyssey346-dev-ansible-ansible/2430mn1ece?form_factor=mobile) | [GitHub](https://pagespeed.web.dev/analysis/https-github-com-ansible-ansible/maetxu2zat?form_factor=mobile) | -| -------- | ---------- | ----------- | -| Performance | 100 | 81 | -| Requests | 3 | 88 | -| Resource Size | 8kb | 629kb | -| Time to Interactive | 0.9s | 2.7s | +| | [GotHub](https://pagespeed.web.dev/analysis/https-gh-psf-lt-ansible-ansible/6ssup87ipo?form_factor=mobile) | [GitHub](https://pagespeed.web.dev/analysis/https-github-com-ansible-ansible/maetxu2zat?form_factor=mobile) | +| ------------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| Performance | 100 | 81 | +| Requests | 3 | 88 | +| Resource Size | 8kb | 629kb | +| Time to Interactive | 0.9s | 2.7s | Quite the difference, isn't it? ## Instances -### Difference between branches -The ``master`` branch runs on the master branch of GotHub. This means that the instance is running a stable, tested version of GotHub that doesn't get updated as much as ``dev``. Doesn't mean they're bad, though. -``dev`` instances run on the dev branch of GotHub. This might mean they are more up-to-date than other instances, but at the same time, they might not be (instance admin might not always update their instance, no auto-updates etc.). You can get the latest and greatest straight out of Git, but you could meet on bugs and other nasty things. -| Link | Cloudflare | Country | ISP | Branch | -| -------- | ---------- | ----------- | ----- | ----- | -| [gh.akisblack.dev](https://gh.akisblack.dev) | No | Germany | OVHcloud | master | -| [gh.odyssey346.dev](https://gh.odyssey346.dev) | No | France | OVHcloud (Trolling Solutions) | master | -| [gh.phreedom.club](https://gh.phreedom.club) | No | Iceland | Flokinet | master | -| [gothub.projectsegfau.lt](https://gothub.projectsegfau.lt) | No | GeoDNS (Luxembourg/USA/India) | BuyVM/Digital Ocean/Airtel | master | -| [gh.riverside.rocks](https://gh.riverside.rocks) | No | USA | Comcast | master | -| [gh.fascinated.cc](https://gh.fascinated.cc) | Yes | Germany | Contabo | master | -| [gothub.lunar.icu](https://gothub.lunar.icu) | Yes | Germany | Unesty | master | -| [gothub.xbdm.fun](https://gothub.xbdm.fun) | Yes | Germany | Hetzner | master | -| [dev.gh.akisblack.dev](https://dev.gh.akisblack.dev) | No | Germany | OVHcloud | dev | -| [gh.creller.net](https://gh.creller.net) | No | Scotland | British Telecommunications PLC | dev | -| [gothub.esmailelbob.xyz](https://gothub.esmailelbob.xyz) | No | Canada | OVHcloud | dev | -| [gothub.no-logs.com](https://gothub.no-logs.com/) | No | Sweden | Vultr | dev | -| [gh.dev.odyssey346.dev](https://gh.dev.odyssey346.dev) | No | France | OVHcloud (Trolling Solutions) | dev | -| [gothub.dev.projectsegfau.lt](https://gothub.dev.projectsegfau.lt) | No | Luxembourg | BuyVM | dev | +### Difference between branches + +The `master` branch runs on the master branch of GotHub. This means that the instance is running a stable, tested version of GotHub that doesn't get updated as much as `dev`. Doesn't mean they're bad, though. + +`dev` instances run on the dev branch of GotHub. This might mean they are more up-to-date than other instances, but at the same time, they might not be (instance admin might not always update their instance, no auto-updates etc.). You can get the latest and greatest straight out of Git, but you could meet on bugs and other nasty things. +| Link | Tor | Cloudflare | Country | ISP | Branch | +| -------- | -------- | ---------- | ----------- | ----- | ----- | +| [gh.bloatcat.tk](https://gh.bloatcat.tk) | No | No | Iceland | 1984 | master | +| [gothub.frontendfriendly.xyz](https://gothub.frontendfriendly.xyz) | No | No | USA | Hetzner | master | +| [gothub.hyperreal.coffee](https://gh.hyperreal.coffee) | No | No | USA | Linode | master | +| [gothub.lunar.icu](https://gothub.lunar.icu) | No | No | Germany | Avoro | master | +| [gothub.no-logs.com](https://gothub.no-logs.com/) | No | No | Sweden | Vultr | master | +| [g.opnxng.com](https://g.opnxng.com/) | No | No | Singapore | Vultr | master | +| [gh.owo.si](https://gh.owo.si/) | [Yes](http://gh.pk47sgwhncn5cgidm7bofngmh7lc7ukjdpk5bjwfemmyp27ovl25ikyd.onion/) | No | Germany | Contabo | master | +| [gothub.projectsegfau.lt](https://gothub.projectsegfau.lt) | [Yes](http://gothub.pjsfkvpxlinjamtawaksbnnaqs2fc2mtvmozrzckxh7f3kis6yea25ad.onion/) | No | GeoDNS (Germany/USA/India) | Avoro/Racknerd/Airtel | master | +| [gh.whateveritworks.org](https://gh.whateveritworks.org) | No | No | Germany | Hetzner | master | +| [gothub.r4fo.com](https://gothub.r4fo.com) | [Yes](http://gothub.r4focoma7gu2zdwwcjjad47ysxt634lg73sxmdbkdozanwqslho5ohyd.onion/) | No | Netherlands | Oracle | master | +| [gothub.dev.projectsegfau.lt](https://gothub.dev.projectsegfau.lt) | [Yes](http://gothub.dev.pjsfkvpxlinjamtawaksbnnaqs2fc2mtvmozrzckxh7f3kis6yea25ad.onion/) | No | India | Airtel | dev | +| [gh.phreedom.club](https://gh.phreedom.club/) | No | No | Iceland | Flokinet | dev | +| [gothub.ducks.party](https://gothub.ducks.party) | No | No | Netherlands | Timeweb | dev | Have an instance you want on the list? Make an issue or PR! You can find a json-list of the same in [gothub/gothub-instances](https://codeberg.org/gothub/gothub-instances). +### Instance rules + +These are the rules an instance must follow to be in our official instance list. + +Most of these rules have been copied from the [invidious project](https://docs.invidious.io/instances). + +- Instance MUST have been updated in the last month. +- Instances using any EXTERNAL DDoS Protection / MITM / Anti-Bot protection MUST be marked as such. +- Instances MUST NOT use any sort of web analytics +- Instances MUST NOT serve ads +- Instances MUST NOT restrict or disallow the access / usage to any natural person (eg. a country's IP range MUST NOT be blocked, access by a natural person MUST NOT be disallowed for arbirary reason) - this rule doesn't apply to juridical persons. + +These rules may change at any time, we will inform the current hosters in the list, and give them 2 weeks so they can correct it + ## Setup + See [gothub.app/docs](https://gothub.app/docs) for information about setting up GotHub. ## Scraping + GotHub utilizes scraping powered by [Colly](http://go-colly.org/) to retrieve information from GitHub for everything except the explore page. By default, GotHub uses Chrome on Windows 10 as the user agent, but you can change it by setting the `GOTHUB_USER_AGENT` environment variable. ## Funding @@ -67,8 +87,3 @@ Our domain [gothub.app](https://gothub.app) is funded by the [Project Segfault]( All content shown on a GotHub instance is from GitHub. Any issues with content shown on a GotHub instance need to be reported to GitHub, not the instance host's internet or domain provider. GitHub is a registered trademark of GitHub, Inc. GotHub is not affiliated with GitHub, Inc. - -## Credits -- [Arya](https://aryak.me) - Main maintainer -- [Midou](https://midou.dev) - GotHub logo and many parts of the frontend -- [Odyssey346](https://odyssey346.dev) - Creator and ex-maintainer diff --git a/cmd/gothub/env.go b/cmd/gothub/env.go index c286fb3..8c37e6b 100644 --- a/cmd/gothub/env.go +++ b/cmd/gothub/env.go @@ -29,6 +29,8 @@ func env() { } else { fmt.Println("Docker: false") } + // Proxying + fmt.Println("Proxying: " + os.Getenv("GOTHUB_PROXYING_ENABLED")) // IP logging fmt.Println("IP logging: " + os.Getenv("GOTHUB_IP_LOGGED")) // URL request logging diff --git a/cmd/gothub/setup.go b/cmd/gothub/setup.go index 08b35e5..734a6e1 100644 --- a/cmd/gothub/setup.go +++ b/cmd/gothub/setup.go @@ -29,6 +29,7 @@ type Vars struct { InstanceCountry string InstanceProvider string CloudflareStatus string + Proxying string } func setup() { @@ -130,6 +131,16 @@ func setup() { vars.CloudflareStatus = "false" } + // ask user whether they want proxying enabled + fmt.Print("Do you want proxying enabled? (y/n) ") + var proxying string + fmt.Scanln(&proxying) + if proxying == "y" { + vars.Proxying = "true" + } else { + vars.Proxying = "false" + } + // save to .env file fmt.Println("Saving environment variables to .env file...") f, err := os.Create(".env") @@ -150,7 +161,8 @@ func setup() { f.WriteString("GOTHUB_INSTANCE_PRIVACY_POLICY=" + vars.PrivacyPolicy + "\n") f.WriteString("GOTHUB_INSTANCE_COUNTRY=" + vars.InstanceCountry + "\n") f.WriteString("GOTHUB_INSTANCE_PROVIDER=" + vars.InstanceProvider + "\n") - f.WriteString("GOTHUB_INSTANCE_CLOUDFLARE=" + vars.CloudflareStatus) + f.WriteString("GOTHUB_INSTANCE_CLOUDFLARE=" + vars.CloudflareStatus + "\n") + f.WriteString("GOTHUB_PROXYING_ENABLED=" + vars.Proxying) println("All done! You can now start your GotHub instance with 'gothub serve'.") println("You can review the environment variables with 'gothub env'.") diff --git a/compose.yml b/compose.yml index a64c0db..ae3ec24 100644 --- a/compose.yml +++ b/compose.yml @@ -1,7 +1,7 @@ version: "3" services: gothub: - image: codeberg.org/gothub/gothub:latest + image: codeberg.org/gothub/gothub:latest # Master branch # image: codeberg.org/gothub/gothub:dev # Dev branch restart: unless-stopped ports: @@ -9,6 +9,7 @@ services: environment: - DOCKER=true - GOTHUB_SETUP_COMPLETE=false + - GOTHUB_PROXYING_ENABLED=true/false - GOTHUB_IP_LOGGED=true/false - GOTHUB_REQUEST_URL_LOGGED=true/false - GOTHUB_USER_AGENT_LOGGED=true/false @@ -21,4 +22,4 @@ services: test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/version || exit 1 interval: 30s timeout: 5s - retries: 2 + retries: 2 \ No newline at end of file diff --git a/go.mod b/go.mod index 1393fe4..9dc1a79 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module codeberg.org/gothub/gothub -go 1.19 +go 1.20 require ( github.com/alecthomas/chroma/v2 v2.7.0 diff --git a/pages/about.go b/pages/about.go index e7ce9bd..fde51c4 100644 --- a/pages/about.go +++ b/pages/about.go @@ -8,6 +8,7 @@ import ( ) type PrivacyInfo struct { + ProxyEnabled string IPAddr string ReqURL string UserAgent string @@ -24,6 +25,7 @@ type PrivacyInfo struct { func HandleAbout(c *fiber.Ctx) error { var privacyInfoArray []PrivacyInfo privacyInfoArray = append(privacyInfoArray, PrivacyInfo{ + ProxyEnabled: os.Getenv("GOTHUB_PROXYING_ENABLED"), IPAddr: os.Getenv("GOTHUB_IP_LOGGED"), ReqURL: os.Getenv("GOTHUB_REQUEST_URL_LOGGED"), UserAgent: os.Getenv("GOTHUB_USER_AGENT_LOGGED"), diff --git a/pages/commit.go b/pages/commit.go new file mode 100644 index 0000000..c270d8f --- /dev/null +++ b/pages/commit.go @@ -0,0 +1,123 @@ +package pages + +import ( + "bufio" + "bytes" + "context" + htmlfmt "github.com/alecthomas/chroma/v2/formatters/html" + "github.com/alecthomas/chroma/v2/lexers" + "github.com/alecthomas/chroma/v2/styles" + "github.com/carlmjohnson/requests" + "github.com/gocolly/colly" + "github.com/gofiber/fiber/v2" + "html/template" + "log" + "net/http" + "os" + "regexp" + "strings" +) + +type Commit struct { + CommitName string + CommitDesc string + CommitHashShortened string + CommitDate string + Commiter []string + CommitToBranch string + PreviousCommit string + Additions int64 + Deletions int64 + ChangedFiles int64 + FullName string +} + +func HandleCommit(c *fiber.Ctx) error { + var commitArray []Commit + + resp, statusErr := http.Get("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/commit/" + c.Params("commit") + "/") + if statusErr != nil { + log.Println(statusErr) + } + if resp.StatusCode == 404 { + // I need a better way to do this + return c.Status(404).Render("error", fiber.Map{ + "title": "Error", + "error": "Commit" + c.Params("commit") + "not found", + }) + } + var file string + url := "https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/commit/" + c.Params("commit") + ".patch" + err := requests. + URL(url). + ToString(&file). + Fetch(context.Background()) + if err != nil { + return c.Status(404).Render("error", fiber.Map{ + "error": err, + }) + } + re := regexp.MustCompile("\\A(?s).*?---(?-s).*\\n") + file = re.ReplaceAllString(file, "---\n") + lexer := lexers.Match("something.diff") + if lexer == nil { + lexer = lexers.Fallback + } + formatter := htmlfmt.New( + htmlfmt.WithClasses(true), + htmlfmt.WithLineNumbers(true), + htmlfmt.PreventSurroundingPre(false), + ) + + buf := bytes.Buffer{} + writer := bufio.NewWriter(&buf) + style := styles.Get("native") + tokens, err := lexer.Tokenise(nil, file) + if err != nil { + return c.Status(500).Render("error", fiber.Map{ + "error": err, + }) + } + formatter.Format(writer, style, tokens) + + cssbuf := bytes.Buffer{} + cssw := bufio.NewWriter(&cssbuf) + formatter.WriteCSS(cssw, style) + writer.Flush() + cssw.Flush() + + // Scraping + Scrape := Commit{} + UserAgent, ok := os.LookupEnv("GOTHUB_USER_AGENT") + if !ok { + UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" + } + + sc := colly.NewCollector(colly.AllowedDomains("github.com"), colly.UserAgent(UserAgent)) + sc.OnHTML("div.commit", func(e *colly.HTMLElement) { + Scrape.CommitName = e.ChildText("div.commit-title") + Scrape.CommitDesc = e.ChildText("div.commit-desc pre") + Scrape.CommitHashShortened = e.ChildText("div.text-lg-right span.m-0 span.sha") + Scrape.PreviousCommit = e.ChildText("div.text-lg-right span.ml-0 a.sha") + Scrape.CommitDate = e.ChildText("div.flex-self-start relative-time") + Scrape.CommitToBranch = e.ChildText("ul.branches-list li.branch a") + e.ForEach("div.flex-self-start .commit-author", func(i int, el *colly.HTMLElement) { + Scrape.Commiter = append(Scrape.Commiter, strings.TrimPrefix(el.Attr("title"), "View all commits by ")) + }) + }) + Scrape.FullName = c.Params("user") + "/" + c.Params("repo") + sc.Visit("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/commit/" + c.Params("commit") + "/") + if len(Scrape.PreviousCommit) > 7 { + Minus := len(Scrape.PreviousCommit) - 7 + Scrape.PreviousCommit = Scrape.PreviousCommit[:len(Scrape.PreviousCommit)-Minus] + } + // Add scrape-based info to commitArray + commitArray = append(commitArray, Scrape) + + return c.Render("commit", fiber.Map{ + "title": "Commit " + Scrape.CommitName + " | " + c.Params("user") + "/" + c.Params("repo"), + "commit": commitArray, + "file": template.HTML(buf.String()), + "css": template.CSS(cssbuf.String()), + }) +} diff --git a/pages/dirview.go b/pages/dirview.go index baf4c7f..3fbb875 100644 --- a/pages/dirview.go +++ b/pages/dirview.go @@ -4,7 +4,8 @@ import ( "log" "net/http" "os" - "strings" + + "github.com/tidwall/gjson" "codeberg.org/gothub/gothub/utils" "github.com/gocolly/colly" @@ -12,21 +13,52 @@ import ( ) type Dir struct { - Readme string - Fullname string - DirName string - Branch string + Readme string + Fullname string + DirName string + Branch string +// TruncationWarning string } +// TODO: Handle repository truncation warning. +// Example text: "Sorry, we had to truncate this directory to 1,000 files. +// 718 entries were omitted from the list. Latest commit info may be omitted." + type DirFiles struct { Name string Path string Type string Branch string Fullname string - DirName string } +// Given a gjson object, as well as branch name and fullname ('user/repository' format), +// return an array of directory files +func return_dir_files_array(dirList gjson.Result, branch string, fullname string) []DirFiles { + var dirFilesArray []DirFiles + + dirList.ForEach(func(i, e gjson.Result) bool { + var FileType string + if e.Get("contentType").Str == "directory" { + FileType = "dir" + } else { + FileType = "file" + } + + dirFilesArray = append(dirFilesArray, DirFiles{ + Name: e.Get("name").Str, + // Path is the path to the file/folder from the repository root + Path: e.Get("path").Str, + Type: FileType, + Branch: branch, + Fullname: fullname, + }) + + return true //keep iterating + }) + return dirFilesArray + +} func DirView(c *fiber.Ctx) error { var dirArray []Dir var dirFilesArray []DirFiles @@ -40,7 +72,7 @@ func DirView(c *fiber.Ctx) error { // I need a better way to do this return c.Status(404).Render("error", fiber.Map{ "title": "Error", - "error": "Directory" + c.Params("+") + "not found", + "error": "Directory " + c.Params("+") + " not found", }) } @@ -56,33 +88,21 @@ func DirView(c *fiber.Ctx) error { } sc := colly.NewCollector(colly.AllowedDomains("github.com"), colly.UserAgent(UserAgent)) - sc.OnHTML("div#readme", func(e *colly.HTMLElement) { - Scrape.Readme = e.ChildText("a[href='#readme']") + + sc.OnHTML("react-app script[data-target]", func(e *colly.HTMLElement) { + jsonMess := e.Text + dirList := gjson.Get(jsonMess, "payload.tree.items") + dirFilesArray = return_dir_files_array(dirList, Scrape.Branch, Scrape.Fullname) }) - sc.OnHTML("div#readme div.Box-body", func(e *colly.HTMLElement) { - Content, _ := e.DOM.Html() - readmeOutput = strings.Replace(strings.Replace(strings.Replace(strings.Replace(string(utils.UGCPolicy().SanitizeBytes([]byte(Content))), "https://github.com", "", -1), "user-content-", "", -1), "https://camo.githubusercontent.com", "/camo", -1), "https://raw.githubusercontent.com", "/raw", -1) - }) - sc.OnHTML("div.js-details-container div.Details-content--hidden-not-important", func(e *colly.HTMLElement) { - e.ForEach("div.js-navigation-item", func(i int, el *colly.HTMLElement) { - var FileType string - if el.ChildAttr("div.flex-shrink-0 svg", "aria-label") == "Directory" { - FileType = "dir" - } else { - FileType = "file" - } - if el.ChildText("div.flex-auto span.d-block a.js-navigation-open") != "" { - dirFilesArray = append(dirFilesArray, DirFiles{ - Name: el.ChildText("div.flex-auto span.d-block a.js-navigation-open"), - Path: el.ChildText("div.flex-auto span.d-block a.js-navigation-open"), - Type: FileType, - Fullname: Scrape.Fullname, - DirName: Scrape.DirName, - Branch: Scrape.Branch, - }) - } + + // Get repository truncation warning. This only works with js enabled, so it does not work with colly + /* + sc.OnHTML("[data-testid='repo-truncation-warning']", func(e *colly.HTMLElement) { + fmt.Printf("Truncation warning: %s", e.Text) + Scrape.TruncationWarning = e.Text }) - }) + */ + sc.Visit("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/tree/" + c.Params("branch") + "/" + c.Params("+")) // Add scrape-based info to dirArray dirArray = append(dirArray, Scrape) diff --git a/pages/fileview.go b/pages/fileview.go index 0f46016..320babb 100644 --- a/pages/fileview.go +++ b/pages/fileview.go @@ -5,12 +5,15 @@ import ( "bytes" "codeberg.org/gothub/gothub/utils" "context" + "encoding/base64" htmlfmt "github.com/alecthomas/chroma/v2/formatters/html" "github.com/alecthomas/chroma/v2/lexers" "github.com/alecthomas/chroma/v2/styles" "github.com/carlmjohnson/requests" "github.com/gofiber/fiber/v2" "html/template" + "net/http" + "path/filepath" ) // FileView is the file view page @@ -27,6 +30,35 @@ func FileView(c *fiber.Ctx) error { }) } + ext := filepath.Ext(c.Params("+")) + // Make an issue for other formats thanks + if ext == ".jpeg" || ext == ".jpg" || ext == ".png" || ext == ".svg" || ext == ".gif" || ext == ".webp" { + data := []byte(file) + dst := make([]byte, base64.StdEncoding.EncodedLen(len(data))) + base64.StdEncoding.Encode(dst, data) + dstStr := string(dst) + // Detect content-type since base64 encoding needs content-type + mimeType := http.DetectContentType(data) + if ext == ".svg" { + mimeType = "image/svg+xml" + } + css := `img { + object-fit: cover; + width: 100%; + height: 250px; + }` + html := " + c.Params(" + return c.Render("file", fiber.Map{ + "title": c.Params("+") + " | " + c.Params("user") + "/" + c.Params("repo"), + "branch": utils.Branch, + "file": html, + "css": css, + "fullname": c.Params("user") + "/" + c.Params("repo"), + "name": c.Params("+"), + "fileBranch": c.Params("branch"), + "type": "img", + }) + } lexer := lexers.Match(c.Params("+")) if lexer == nil { lexer = lexers.Fallback @@ -64,5 +96,6 @@ func FileView(c *fiber.Ctx) error { "fullname": c.Params("user") + "/" + c.Params("repo"), "name": c.Params("+"), "fileBranch": c.Params("branch"), + "type": "code", }) } diff --git a/pages/repo.go b/pages/repo.go index c7dc8d6..f10b0a7 100644 --- a/pages/repo.go +++ b/pages/repo.go @@ -6,11 +6,19 @@ import ( "os" "strings" + "github.com/tidwall/gjson" + "codeberg.org/gothub/gothub/utils" "github.com/gocolly/colly" "github.com/gofiber/fiber/v2" ) +type Languages struct { + Name string + Percent string + Color string +} + type Repo struct { Fullname string Description string @@ -18,8 +26,9 @@ type Repo struct { Stars string Forks string CommitsBehind string + CommitsAhead string Watchers string - Language []string + Language []Languages License string DefaultBranch string Readme string @@ -56,7 +65,6 @@ func HandleRepo(c *fiber.Ctx) error { "error": "Repository " + c.Params("user") + "/" + repoUrl + branchExists + " not found", }) } - // Scraping Scrape := Repo{} @@ -79,18 +87,55 @@ func HandleRepo(c *fiber.Ctx) error { }) }) sc.OnHTML("div.Box-body div.d-flex div span", func(e *colly.HTMLElement) { - Scrape.CommitsBehind = strings.TrimSuffix(e.ChildText("a"), " commits behind") + Scrape.CommitsBehind = strings.TrimSuffix(e.ChildText("a[data-analytics-event*='Behind Compare']"), " commits behind") + Scrape.CommitsAhead = strings.TrimSuffix(e.ChildText("a[data-analytics-event*='Ahead Compare']"), " commits ahead") }) sc.OnHTML("div#readme", func(e *colly.HTMLElement) { Scrape.Readme = e.ChildText("a[href='#readme']") }) - sc.OnHTML("div#readme div.Box-body", func(e *colly.HTMLElement) { - Content, _ := e.DOM.Html() - readmeOutput = strings.Replace(strings.Replace(strings.Replace(strings.Replace(string(utils.UGCPolicy().SanitizeBytes([]byte(Content))), "https://github.com", "", -1), "user-content-", "", -1), "https://camo.githubusercontent.com", "/camo", -1), "https://raw.githubusercontent.com", "/raw", -1) + + // jq '.props.initialPayload.overview.overviewFiles[]|select(.tabName == "README").richText' + sc.OnHTML("div.Layout-main react-partial script", func(e *colly.HTMLElement) { + jsonMess := e.Text + + result := gjson.Get(jsonMess, "props.initialPayload.overview.overviewFiles") + result.ForEach(func(i, e gjson.Result) bool { + if e.Get("tabName").Str == "README" { + unsanitizedOutput := e.Get("richText").Str + readmeOutput = strings.Replace(strings.Replace(strings.Replace(strings.Replace(strings.Replace(string(utils.UGCPolicy().SanitizeBytes([]byte(unsanitizedOutput))), "https://github.com", "", -1), "user-content-", "", -1), "https://camo.githubusercontent.com", "/camo", -1), "https://raw.githubusercontent.com", "/raw", -1), "https://user-images.githubusercontent.com", "/user-images", -1) + return false + } + return true // keep iterating + }) + result = gjson.Get(jsonMess, "props.initialPayload.tree.items") + //jq '.props.initialPayload.tree.items' + result.ForEach(func(i, e gjson.Result) bool { + var FileType string + if e.Get("contentType").Str == "directory" { + FileType = "dir" + } else { + FileType = "file" + } + + repoFilesArray = append(repoFilesArray, RepoFiles{ + Name: e.Get("name").Str, + Path: e.Get("path").Str, + Type: FileType, + DefaultBranch: gjson.Get(jsonMess, "props.initialPayload.repo.defaultBranch").Str, + Fullname: Scrape.Fullname, + }) + + return true //keep iterating + }) }) + sc.OnHTML("div.BorderGrid-cell ul.list-style-none", func(e *colly.HTMLElement) { e.ForEach("li.d-inline .d-inline-flex", func(i int, el *colly.HTMLElement) { - Scrape.Language = append(Scrape.Language, el.ChildText("span.text-bold")+" "+el.ChildText("span:contains('%')")) + var lang Languages + lang.Name = el.ChildText("span.text-bold") + lang.Percent = el.ChildText("span:contains('%')") + lang.Color = strings.ReplaceAll(strings.ReplaceAll(el.ChildAttr("svg", "style"), "color:", ""), ";", "") + Scrape.Language = append(Scrape.Language, lang) }) }) sc.OnHTML("div#repository-container-header", func(e *colly.HTMLElement) { @@ -99,24 +144,8 @@ func HandleRepo(c *fiber.Ctx) error { sc.OnHTML("summary[title*='Switch branches or tags']", func(e *colly.HTMLElement) { Scrape.DefaultBranch = e.ChildText("span.css-truncate-target") }) - sc.OnHTML("div.js-details-container div.Details-content--hidden-not-important", func(e *colly.HTMLElement) { - e.ForEach("div.js-navigation-item", func(i int, el *colly.HTMLElement) { - var FileType string - if el.ChildAttr("div.flex-shrink-0 svg", "aria-label") == "Directory" { - FileType = "dir" - } else { - FileType = "file" - } - repoFilesArray = append(repoFilesArray, RepoFiles{ - Name: el.ChildText("div.flex-auto span.d-block a.js-navigation-open"), - Path: el.ChildText("div.flex-auto span.d-block a.js-navigation-open"), - Type: FileType, - Fullname: Scrape.Fullname, - DefaultBranch: Scrape.DefaultBranch, - }) - }) - }) sc.Visit("https://github.com/" + c.Params("user") + "/" + repoUrl + branchExists) + // Add scrape-based info to repoArray repoArray = append(repoArray, Scrape) return c.Render("repo", fiber.Map{ diff --git a/pages/user.go b/pages/user.go index a96b2ce..562f1db 100644 --- a/pages/user.go +++ b/pages/user.go @@ -158,6 +158,7 @@ func HandleUser(c *fiber.Ctx) error { sc.OnHTML("article.markdown-body", func(e *colly.HTMLElement) { Content, _ := e.DOM.Html() Scrape.Readme = strings.Replace(strings.Replace(strings.Replace(strings.Replace(string(utils.UGCPolicy().SanitizeBytes([]byte(Content))), "https://github.com", "", -1), "user-content-", "", -1), "https://camo.githubusercontent.com", "/camo", -1), "https://raw.githubusercontent.com", "/raw", -1) + }) sc.OnHTML("div.text-mono", func(e *colly.HTMLElement) { Scrape.ReadmeUrl = strings.Replace(e.ChildAttr("a", "href"), "tree", "blob", -1) diff --git a/pages/wiki.go b/pages/wiki.go new file mode 100644 index 0000000..543b500 --- /dev/null +++ b/pages/wiki.go @@ -0,0 +1,87 @@ +package pages + +import ( + "codeberg.org/gothub/gothub/utils" + "github.com/gocolly/colly" + "github.com/gofiber/fiber/v2" + "log" + "net/http" + "os" + "regexp" + "strings" +) + +type Wiki struct { + RepoUser string + RepoName string + Title string + LastEdit string + LastEditor string + RevisionNum string + PageNum string + PageContent string + Sidebar []Sidebar +} +type Sidebar struct { + Name string + Link string +} + +func WikiView(c *fiber.Ctx) error { + var wikiArray []Wiki + + resp, statusErr := http.Get("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/wiki/" + c.Params("page")) + if statusErr != nil { + log.Println(statusErr) + } + if resp.StatusCode == 404 { + // I need a better way to do this + return c.Status(404).Render("error", fiber.Map{ + "title": "Error", + "error": "Wiki" + c.Params("page") + "not found", + }) + } + + // Scraping + Scrape := Wiki{} + + UserAgent, ok := os.LookupEnv("GOTHUB_USER_AGENT") + if !ok { + UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" + } + + sc := colly.NewCollector(colly.AllowedDomains("github.com"), colly.UserAgent(UserAgent)) + sc.OnHTML("div#repository-container-header", func(e *colly.HTMLElement) { + Scrape.RepoUser = e.ChildText("span.author a") + Scrape.RepoName = e.ChildText("strong a") + }) + sc.OnHTML("div#wiki-wrapper", func(e *colly.HTMLElement) { + Scrape.Title = e.ChildText("div.d-flex h1") + Scrape.LastEdit = e.ChildText("div.gh-header-meta relative-time") + re := regexp.MustCompile(`\ edited.*`) + Scrape.LastEditor = re.ReplaceAllString(strings.Replace(e.ChildText("div.gh-header-meta"), "\n", "", -1), "${1}") + Scrape.RevisionNum = strings.TrimSuffix(e.ChildText("a.Link--muted"), " revisions") + }) + sc.OnHTML("div.wiki-pages-box div.Box--condensed", func(e *colly.HTMLElement) { + Scrape.PageNum = e.ChildText("span.Counter--primary") + e.ForEach("ul.list-style-none li.Box-row", func(i int, el *colly.HTMLElement) { + Scrape.Sidebar = append(Scrape.Sidebar, Sidebar{ + Name: el.ChildText("summary span a.Truncate-text"), + Link: el.ChildAttr("summary span a.Truncate-text", "href"), + }) + }) + }) + sc.OnHTML("div#wiki-body > div.markdown-body", func(e *colly.HTMLElement) { + Content, _ := e.DOM.Html() + Scrape.PageContent = strings.Replace(strings.Replace(strings.Replace(strings.Replace(strings.Replace(string(utils.UGCPolicy().SanitizeBytes([]byte(Content))), "https://github.com", "", -1), "user-content-", "", -1), "https://camo.githubusercontent.com", "/camo", -1), "https://raw.githubusercontent.com", "/raw", -1), "https://user-images.githubusercontent.com", "/user-images", -1) + + }) + sc.Visit("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/wiki/" + c.Params("page")) + // Add scrape-based info to wikiArray + wikiArray = append(wikiArray, Scrape) + + return c.Render("wiki", fiber.Map{ + "title": "Wiki page " + c.Params("page") + " | " + c.Params("user") + "/" + c.Params("repo"), + "wiki": wikiArray, + }) +} diff --git a/public/css/global.css b/public/css/global.css index b01effb..f89f031 100644 --- a/public/css/global.css +++ b/public/css/global.css @@ -6,12 +6,14 @@ --secondary-background: #353535; --background-darker: #151515; --accent: #00b7c3; - --yellow: #8B8000; + --yellow: #8b8000; color-scheme: dark; } body { - font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif; + font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, + helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, + sans-serif; color: var(--text); background-color: var(--background-darker); transition: ease-in-out 0.25s; @@ -32,6 +34,20 @@ main { margin: 0 24vw; } +.margin-ow { + margin: 0 12vw; +} + +pre { + overflow: scroll; + background: var(--secondary-background); + border-radius: 4px; + padding: 4px; +} + +#wrap { + display: flex; +} .navbar { display: flex; align-items: center; @@ -73,7 +89,9 @@ main { background-color: var(--background); padding: 8px; border-radius: 4px; - font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif; + font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, + helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, + sans-serif; color: var(--text); } @@ -95,7 +113,9 @@ a:hover { background-color: var(--yellow); padding: 8px; border-radius: 4px; - font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif; + font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, + helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, + sans-serif; color: var(--text); } @@ -111,7 +131,8 @@ a:hover { /* URI: /explore */ -.explore-card, .user-repo-card { +.explore-card, +.user-repo-card { background-color: var(--background); padding: 8px; border-radius: 4px; @@ -125,7 +146,8 @@ a:hover { transition: ease-in-out 0.25s; } -.explore-card:hover, .user-repo-card:hover { +.explore-card:hover, +.user-repo-card:hover { background-color: var(--secondary-background); color: var(--text); } @@ -147,6 +169,7 @@ a:hover { margin: 4px; word-wrap: nowrap; text-overflow: ellipsis; + overflow-wrap: anywhere; } .user-profile h2 { @@ -211,6 +234,20 @@ a:hover { color: var(--text); } +.lang-bar:last-child { + margin-bottom: 0; +} + +.lang-bar { + width: 100%; + display: inherit; + height: 10px; + border-radius:4px; + overflow: hidden; /* To force the corners to be round. */ + user-select: none; /* Prevent the selection */ + -webkit-user-select: none; /* Safari specific fix. */ +} + /* URI: /:user/:repo */ .button { background-color: var(--background); @@ -266,6 +303,23 @@ a:hover { background-color: var(--secondary-background); } +/* Overwrite */ + +.no-margin { + margin: 0; +} + +.no-padding { + padding: 0; +} + +.float-right { + float: right; + display: grid; + flex: none; + align-self: flex-start; +} + @media screen and (prefers-color-scheme: light) { :root { --text: #000; @@ -293,6 +347,16 @@ a:hover { margin: 8px; } + #wrap { + display: flex; + flex-direction: column; + } + + .float-right { + float: none; + display: inline-grid; + } + .navbar-slogan { display: none; } @@ -312,5 +376,5 @@ a:hover { } } .cl { - padding-left: 8px + padding-left: 8px; } diff --git a/serve/serve.go b/serve/serve.go index 3c0fcdc..d2091ef 100644 --- a/serve/serve.go +++ b/serve/serve.go @@ -15,6 +15,8 @@ import ( "github.com/gofiber/fiber/v2/middleware/cache" "github.com/gofiber/fiber/v2/middleware/compress" "github.com/gofiber/fiber/v2/middleware/limiter" + // For debugging purposes + // "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/recover" "github.com/gofiber/template/html" @@ -62,6 +64,10 @@ func Serve(port string) { app.Use(cache.New(cache.Config{ Expiration: 5 * time.Minute, })) + // For debugging purposes + // app.Use(logger.New(logger.Config{ + // Format: "[${ip}]:${port} ${status} - ${method} ${path} ${queryParams}\n", + // })) app.Use(compress.New(compress.Config{ Level: compress.LevelBestSpeed, // 1 @@ -86,13 +92,21 @@ func Serve(port string) { MaxAge: 31536000, } + proxying, ok := os.LookupEnv("GOTHUB_PROXYING_ENABLED") + if !ok { + proxying = "true" + } // add global headers app.Use(func(c *fiber.Ctx) error { c.Set("X-Frame-Options", "SAMEORIGIN") c.Set("X-XSS-Protection", "1; mode=block") c.Set("X-Content-Type-Options", "nosniff") c.Set("Referrer-Policy", "no-referrer") - c.Set("Content-Security-Policy", "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data; font-src 'self'; script-src 'self'; frame-ancestors 'self'; form-action 'self'; base-uri 'self'; connect-src 'self';") + if proxying == "true" { + c.Set("Content-Security-Policy", "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; script-src 'self'; frame-ancestors 'self'; form-action 'self'; base-uri 'self'; connect-src 'self';") + } else { + c.Set("Content-Security-Policy", "default-src 'self' https://camo.githubusercontent.com https://avatars.githubusercontent.com https://user-images.githubusercontent.com https://github.com https://raw.githubusercontent.com https://gist.github.com; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://user-images.githubusercontent.com https://camo.githubusercontent.com https://avatars.githubusercontent.com https://gist.github.com; font-src 'self'; connect-src 'self' https://user-images.githubusercontent.com https://camo.githubusercontent.com https://avatars.githubusercontent.com https://github.com https://raw.githubusercontent.com https://gist.github.com; frame-ancestors 'self'; form-action 'self'; base-uri 'self'") + } c.Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload") return c.Next() @@ -107,30 +121,98 @@ func Serve(port string) { app.Get("/explore", ratelimiter, pages.HandleExplore) app.Get("/:user", pages.HandleUser) app.Get("/avatar/:id", func(c *fiber.Ctx) error { - utils.ProxyRequest(c, "https://avatars.githubusercontent.com/u/"+c.Params("id")+"?v=4") - return nil + if proxying == "true" { + utils.ProxyRequest(c, "https://avatars.githubusercontent.com/u/"+c.Params("id")+"?v=4") + return nil + } else { + c.Redirect("https://avatars.githubusercontent.com/u/" + c.Params("id") + "?v=4") + return nil + } + }) + app.Get("/user-images/:id/:img", func(c *fiber.Ctx) error { + if proxying == "true" { + utils.ProxyRequest(c, "https://user-images.githubusercontent.com/"+c.Params("id")+"/"+c.Params("img")+"?v=4") + return nil + } else { + c.Redirect("https://user-images.githubusercontent.com/" + c.Params("id") + "/" + c.Params("img") + "?v=4") + return nil + } }) app.Get("/:user/:repo", pages.HandleRepo) + app.Get("/:user/:repo/commit/:commit", pages.HandleCommit) + app.Get("/diff/:user/:repo/commit/:commit", func(c *fiber.Ctx) error { + if proxying == "true" { + utils.ProxyRequest(c, "https://github.com/"+c.Params("user")+"/"+c.Params("repo")+"/commit/"+c.Params("commit")+".diff") + return nil + } else { + c.Redirect("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/commit/" + c.Params("commit") + ".diff") + return nil + } + }) + app.Get("/:user/:repo/info/+", func(c *fiber.Ctx) error { + // This is needed but it looks like git doesn't send it. Or maybe i just shouldn't program at midnight + param := "?service=git-upload-pack" + if proxying == "true" { + utils.ProxyRequest(c, "https://github.com/"+c.Params("user")+"/"+c.Params("repo")+".git/info/"+c.Params("+")+param) + return nil + } else { + c.Redirect("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + ".git/info/" + c.Params("+") + param) + return nil + } + }) + app.Post("/:user/:repo/git-upload-pack", func(c *fiber.Ctx) error { + if proxying == "true" { + utils.ProxyRequest(c, "https://github.com/"+c.Params("user")+"/"+c.Params("repo")+".git/git-upload-pack") + return nil + } else { + c.Redirect("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + ".git/git-upload-pack") + return nil + } + }) app.Get("/:user/:repo/blob/:branch/+", pages.FileView) app.Get("/:user/:repo/tree/:branch/+", pages.DirView) - app.Get("/:user/:repo/tree/:branch", pages.HandleRepo) - app.Get("/download/:user/:repo/:branch", func(c *fiber.Ctx) error { - utils.ProxyRequest(c, "https://github.com/"+c.Params("user")+"/"+c.Params("repo")+"/archive/"+c.Params("branch")+".zip") + app.Get("/:user/:repo/wiki", func(c *fiber.Ctx) error { + c.Redirect("/" + c.Params("user") + "/" + c.Params("repo") + "/wiki/Home") return nil }) + app.Get("/:user/:repo/wiki/:page", pages.WikiView) + app.Get("/:user/:repo/tree/:branch", pages.HandleRepo) + app.Get("/:user/:repo/archive/:branch", func(c *fiber.Ctx) error { + if proxying == "true" { + utils.ProxyRequest(c, "https://github.com/"+c.Params("user")+"/"+c.Params("repo")+"/archive/"+c.Params("branch")) + return nil + } else { + c.Redirect("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/archive/" + c.Params("branch")) + return nil + } + }) + app.Get("/raw/:user/:repo/:branch/+", func(c *fiber.Ctx) error { + if proxying == "true" { + utils.ProxyRequest(c, "https://raw.githubusercontent.com/"+c.Params("user")+"/"+c.Params("repo")+"/"+c.Params("branch")+"/"+c.Params("+")) + return nil + } else { + c.Redirect("https://raw.githubusercontent.com/" + c.Params("user") + "/" + c.Params("repo") + "/" + c.Params("branch") + "/" + c.Params("+")) + return nil + } + }) app.Get("/camo/:p1/:p2", func(c *fiber.Ctx) error { - utils.ProxyRequest(c, "https://camo.githubusercontent.com/"+c.Params("p1")+"/"+c.Params("p2")) - return nil + if proxying == "true" { + utils.ProxyRequest(c, "https://camo.githubusercontent.com/"+c.Params("p1")+"/"+c.Params("p2")) + return nil + } else { + c.Redirect("https://camo.githubusercontent.com/" + c.Params("p1") + "/" + c.Params("p2")) + return nil + } }) app.Get("/gist/:user/:gistID", pages.HandleGist) app.Get("/download/gist/:user/:gistID/:revision", func(c *fiber.Ctx) error { - utils.ProxyRequest(c, "https://gist.github.com/"+c.Params("user")+"/"+c.Params("gistID")+"/archive/"+c.Params("revision")+".zip") - return nil - }) - - app.Get("/raw/:user/:repo/:branch/:file", func(c *fiber.Ctx) error { - utils.ProxyRequest(c, "https://raw.githubusercontent.com/"+c.Params("user")+"/"+c.Params("repo")+"/"+c.Params("branch")+"/"+c.Params("file")) - return nil + if proxying == "true" { + utils.ProxyRequest(c, "https://gist.github.com/"+c.Params("user")+"/"+c.Params("gistID")+"/archive/"+c.Params("revision")+".zip") + return nil + } else { + c.Redirect("https://gist.github.com/" + c.Params("user") + "/" + c.Params("gistID") + "/archive/" + c.Params("revision") + ".zip") + return nil + } }) api := app.Group("/api") diff --git a/views/about.html b/views/about.html index abf80a0..fe30323 100644 --- a/views/about.html +++ b/views/about.html @@ -10,6 +10,7 @@

If this page isn't filled, please contact your instance's maintainer.