-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathgithub.go
98 lines (88 loc) · 2.42 KB
/
github.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package main
import (
"errors"
"fmt"
"net/http"
"strings"
"time"
)
func githubMode(w http.ResponseWriter, r *http.Request) (err error) {
ua := r.UserAgent()
// GitHub uses camo, see:
// https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-anonymized-urls
if !strings.Contains(ua, "github-camo") {
err = errors.New("origin not allowed, require github")
return
}
locs, ok := r.URL.Query()["repo"]
if !ok {
err = errors.New("missing location query parameter")
return
}
loc := locs[0]
ss := strings.Split(loc, "/")
if len(ss) != 2 {
err = errors.New("invalid input, require username/repo")
return
}
// Only allow specified users, maybe allow more in the future.
if !source.isAllowed(ss[0], false) {
err = errors.New("username is not allowed, please contact @changkun")
return
}
// Currently we always perform a reuqest to github and double check
// if the repo exists. This is necessary because a repo might not
// exist, moved, or deleted.
repoPath := fmt.Sprintf("%s/%s", "https://github.com", loc)
resp, err := http.Get(repoPath)
if err != nil {
err = fmt.Errorf("failed to request github: %w", err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK &&
resp.StatusCode != http.StatusMovedPermanently {
err = fmt.Errorf("%s is not a GitHub repository", repoPath)
return
}
// Figure out the new location if the repo is moved
if resp.StatusCode == http.StatusMovedPermanently {
repoPath = resp.Header.Get("Location")
}
var cookieVid string
c, err := r.Cookie(urlstatCookieVid)
if err != nil {
cookieVid = ""
} else {
cookieVid = c.Value
}
var vid string
col := db.Database(dbname).Collection("github.com")
vid, err = saveVisit(r.Context(), col, &visit{
VisitorID: cookieVid,
Path: repoPath,
IP: readIP(r),
UA: ua,
Time: time.Now().UTC(),
})
if err != nil {
err = fmt.Errorf("failed to save visit: %w", err)
return
}
if cookieVid == "" && vid != "" {
w.Header().Set("Set-Cookie", urlstatCookieVid+"="+vid)
}
pv, _, err := countVisit(r.Context(), col, repoPath, "page")
if err != nil {
err = fmt.Errorf("failed to count visit: %w", err)
return
}
badge, err := drawer.RenderBytes("visitors", fmt.Sprintf("%d", pv), colorBlue)
if err != nil {
err = fmt.Errorf("failed to render stat badge: %w", err)
return
}
w.Header().Set("Content-Type", "image/svg+xml")
w.Write(badge)
return nil
}