-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathmain.go
123 lines (102 loc) · 4.01 KB
/
main.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Copyright 2021 Teal.Finance/Rainbow contributors
// This file is part of Teal.Finance/Rainbow,
// a screener for DeFi options under the MIT License.
// SPDX-License-Identifier: MIT
package main
import (
"net/http"
"time"
"github.com/go-chi/chi/v5"
"github.com/teal-finance/emo"
"github.com/teal-finance/garcon"
"github.com/teal-finance/garcon/gg"
"github.com/teal-finance/rainbow/pkg/provider"
"github.com/teal-finance/rainbow/pkg/rainbow"
"github.com/teal-finance/rainbow/pkg/rainbow/api"
"github.com/teal-finance/rainbow/pkg/rainbow/storage/dbram"
)
var log = emo.NewZone("main")
func main() {
emo.GlobalTimestamp(true)
parseFlags()
names := listProviderNames()
log.Init("Providers:", names)
g := garcon.New(
garcon.WithURLs(gg.SplitClean(*mainAddr)...),
garcon.WithDev(*dev))
// start the service in background
providers := provider.Select(names, g.ServerName.String(), *alert)
service := rainbow.NewService(providers, dbram.NewDB())
go service.Run(*period)
// chain middleware
middleware, connState := g.StartExporter(*expPort)
middleware = middleware.Append(
g.MiddlewareRejectUnprintableURI(),
g.MiddlewareLogRequest(),
g.MiddlewareRateLimiter(*reqBurst, *reqPerMinute),
g.MiddlewareCORS(),
g.MiddlewareServerHeader("Rainbow"))
// middleware to set/check cookies
var ck garcon.TokenChecker
if len(*aes) > 0 {
ck = g.IncorruptibleChecker(*aes, 0, true)
} else {
ck = g.JWTChecker(*hmac, "FreePlan", 10, "PremiumPlan", 100)
}
// delete secrets (no longer required)
aes = nil
hmac = nil
router := chi.NewRouter()
// Static website
ws := g.NewStaticWebServer(*wwwDir)
// set the cookie when visiting index.html (NotFound = catches index.html and other Vue sub-folders)
router.With(ck.Set).NotFound(ws.ServeFile("index.html", "text/html; charset=utf-8"))
// protect web files: reject invalid cookie
router.With(ck.Chk).Get("/js/*", ws.ServeDir("text/javascript; charset=utf-8"))
router.With(ck.Chk).Get("/assets/*", ws.ServeAssets())
router.With(ck.Chk).Get("/version", garcon.ServeVersion())
// do not protect favicon and other public images
router.Get("/favicon.ico", ws.ServeFile("favicon.ico", "image/x-icon"))
router.Get("/favicon.png", ws.ServeFile("favicon.png", "image/png"))
router.Get("/img/*", ws.ServeImages())
// Disable the contact-form endpoint until we protect it against DoS
if false {
cf := g.NewContactForm("/about") // submitted contact-form redirects to "/about"
router.With(ck.Chk).Post("/submit", cf.Notify(*form)) // forward contact-form to Mattermost
}
// API routes
router.Route("/v0", func(r chi.Router) {
h := api.NewHandler(&service)
// HTTP API for Jupyter notebooks
r.With(ck.Vet).Route("/options", func(r chi.Router) {
r.HandleFunc("/", h.Options)
r.HandleFunc("/{asset}", h.Options)
r.HandleFunc("/{asset}/", h.Options)
r.HandleFunc("/{asset}/{expiry}", h.Options)
r.HandleFunc("/{asset}/{expiry}/", h.Options)
r.HandleFunc("/{asset}/{expiry}/{provider}", h.Options)
r.HandleFunc("/{asset}/{expiry}/{provider}/", h.Options)
r.HandleFunc("/{asset}/{expiry}/{provider}/{format}", h.Options)
r.HandleFunc("/{asset}/{expiry}/{provider}/{format}/", h.Options)
})
// HTTP API using the Backend-For-Frontend pattern
r.With(ck.Vet).Get("/bff/cp", h.CallPut)
// GraphQL API to display the screener on a web page
r.With(ck.Vet).Mount("/graphql", h.GraphQLHandler())
if *dev { // interactive GraphQL API in dev. mode only
r.Mount("/graphiql", api.InteractiveGQLHandler("/v0/graphql"))
}
})
server := http.Server{
Addr: listenAddr,
Handler: middleware.Then(router),
ReadTimeout: time.Second,
ReadHeaderTimeout: time.Second,
WriteTimeout: time.Minute, // Garcon.MiddlewareRateLimiter() delays responses, so people (attackers) who click frequently will wait longer.
IdleTimeout: time.Second,
ConnState: connState,
ErrorLog: log.Default(),
}
log.Print("Server listening on http://localhost" + server.Addr)
log.Fatal(server.ListenAndServe())
}