forked from Gitlink/gitea_hat
新增:路由定义
This commit is contained in:
parent
3e5b2a738c
commit
da9cd18f74
|
@ -0,0 +1,273 @@
|
|||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
_ "net/http/pprof" // Used for debugging if enabled and a web server is running
|
||||
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/routers"
|
||||
"code.gitea.io/gitea/routers/install"
|
||||
hat_routers "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers"
|
||||
"github.com/felixge/fgprof"
|
||||
"github.com/urfave/cli"
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
// CmdWeb represents the available web sub-command.
|
||||
var CmdWeb = cli.Command{
|
||||
Name: "web",
|
||||
Usage: "Start Gitea web server",
|
||||
Description: `Gitea web server is the only thing you need to run,
|
||||
and it takes care of all the other things for you`,
|
||||
Action: runWeb,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "port, p",
|
||||
Value: "3000",
|
||||
Usage: "Temporary port number to prevent conflict",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "install-port",
|
||||
Value: "3000",
|
||||
Usage: "Temporary port number to run the install page on to prevent conflict",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "pid, P",
|
||||
Value: setting.PIDFile,
|
||||
Usage: "Custom pid file path",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "Only display Fatal logging errors until logging is set-up",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "verbose",
|
||||
Usage: "Set initial logging to TRACE level until logging is properly set-up",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func runHTTPRedirector() {
|
||||
_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), "Web: HTTP Redirector", process.SystemProcessType, true)
|
||||
defer finished()
|
||||
|
||||
source := fmt.Sprintf("%s:%s", setting.HTTPAddr, setting.PortToRedirect)
|
||||
dest := strings.TrimSuffix(setting.AppURL, "/")
|
||||
log.Info("Redirecting: %s to %s", source, dest)
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
target := dest + r.URL.Path
|
||||
if len(r.URL.RawQuery) > 0 {
|
||||
target += "?" + r.URL.RawQuery
|
||||
}
|
||||
http.Redirect(w, r, target, http.StatusTemporaryRedirect)
|
||||
})
|
||||
|
||||
err := runHTTP("tcp", source, "HTTP Redirector", handler)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to start port redirection: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func runWeb(ctx *cli.Context) error {
|
||||
if ctx.Bool("verbose") {
|
||||
_ = log.DelLogger("console")
|
||||
log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "trace", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout))
|
||||
} else if ctx.Bool("quiet") {
|
||||
_ = log.DelLogger("console")
|
||||
log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "fatal", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout))
|
||||
}
|
||||
defer func() {
|
||||
if panicked := recover(); panicked != nil {
|
||||
log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2))
|
||||
}
|
||||
}()
|
||||
|
||||
managerCtx, cancel := context.WithCancel(context.Background())
|
||||
graceful.InitManager(managerCtx)
|
||||
defer cancel()
|
||||
|
||||
if os.Getppid() > 1 && len(os.Getenv("LISTEN_FDS")) > 0 {
|
||||
log.Info("Restarting Gitea on PID: %d from parent PID: %d", os.Getpid(), os.Getppid())
|
||||
} else {
|
||||
log.Info("Starting Gitea on PID: %d", os.Getpid())
|
||||
}
|
||||
|
||||
// Set pid file setting
|
||||
if ctx.IsSet("pid") {
|
||||
setting.PIDFile = ctx.String("pid")
|
||||
setting.WritePIDFile = true
|
||||
}
|
||||
|
||||
// Perform pre-initialization
|
||||
needsInstall := install.PreloadSettings(graceful.GetManager().HammerContext())
|
||||
if needsInstall {
|
||||
// Flag for port number in case first time run conflict
|
||||
if ctx.IsSet("port") {
|
||||
if err := setPort(ctx.String("port")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if ctx.IsSet("install-port") {
|
||||
if err := setPort(ctx.String("install-port")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
c := install.Routes()
|
||||
err := listen(c, false)
|
||||
if err != nil {
|
||||
log.Critical("Unable to open listener for installer. Is Gitea already running?")
|
||||
graceful.GetManager().DoGracefulShutdown()
|
||||
}
|
||||
select {
|
||||
case <-graceful.GetManager().IsShutdown():
|
||||
<-graceful.GetManager().Done()
|
||||
log.Info("PID: %d Gitea Web Finished", os.Getpid())
|
||||
log.Close()
|
||||
return err
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
NoInstallListener()
|
||||
}
|
||||
|
||||
if setting.EnablePprof {
|
||||
go func() {
|
||||
http.DefaultServeMux.Handle("/debug/fgprof", fgprof.Handler())
|
||||
_, _, finished := process.GetManager().AddTypedContext(context.Background(), "Web: PProf Server", process.SystemProcessType, true)
|
||||
log.Info("Starting pprof server on localhost:6060")
|
||||
log.Info("%v", http.ListenAndServe("localhost:6060", nil))
|
||||
finished()
|
||||
}()
|
||||
}
|
||||
|
||||
log.Info("Global init")
|
||||
// Perform global initialization
|
||||
setting.LoadFromExisting()
|
||||
routers.GlobalInitInstalled(graceful.GetManager().HammerContext())
|
||||
|
||||
// We check that AppDataPath exists here (it should have been created during installation)
|
||||
// We can't check it in `GlobalInitInstalled`, because some integration tests
|
||||
// use cmd -> GlobalInitInstalled, but the AppDataPath doesn't exist during those tests.
|
||||
if _, err := os.Stat(setting.AppDataPath); err != nil {
|
||||
log.Fatal("Can not find APP_DATA_PATH '%s'", setting.AppDataPath)
|
||||
}
|
||||
|
||||
// Override the provided port number within the configuration
|
||||
if ctx.IsSet("port") {
|
||||
if err := setPort(ctx.String("port")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Set up Chi routes
|
||||
c := routers.NormalRoutes()
|
||||
hat_routers.InitHatRouters(c)
|
||||
err := listen(c, true)
|
||||
<-graceful.GetManager().Done()
|
||||
log.Info("PID: %d Gitea Web Finished", os.Getpid())
|
||||
log.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
func setPort(port string) error {
|
||||
setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, port, 1)
|
||||
setting.HTTPPort = port
|
||||
|
||||
switch setting.Protocol {
|
||||
case setting.HTTPUnix:
|
||||
case setting.FCGI:
|
||||
case setting.FCGIUnix:
|
||||
default:
|
||||
defaultLocalURL := string(setting.Protocol) + "://"
|
||||
if setting.HTTPAddr == "0.0.0.0" {
|
||||
defaultLocalURL += "localhost"
|
||||
} else {
|
||||
defaultLocalURL += setting.HTTPAddr
|
||||
}
|
||||
defaultLocalURL += ":" + setting.HTTPPort + "/"
|
||||
|
||||
// Save LOCAL_ROOT_URL if port changed
|
||||
setting.CreateOrAppendToCustomConf(func(cfg *ini.File) {
|
||||
cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func listen(m http.Handler, handleRedirector bool) error {
|
||||
listenAddr := setting.HTTPAddr
|
||||
if setting.Protocol != setting.HTTPUnix && setting.Protocol != setting.FCGIUnix {
|
||||
listenAddr = net.JoinHostPort(listenAddr, setting.HTTPPort)
|
||||
}
|
||||
_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), "Web: Gitea Server", process.SystemProcessType, true)
|
||||
defer finished()
|
||||
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL)
|
||||
// This can be useful for users, many users do wrong to their config and get strange behaviors behind a reverse-proxy.
|
||||
// A user may fix the configuration mistake when he sees this log.
|
||||
// And this is also very helpful to maintainers to provide help to users to resolve their configuration problems.
|
||||
log.Info("AppURL(ROOT_URL): %s", setting.AppURL)
|
||||
|
||||
if setting.LFS.StartServer {
|
||||
log.Info("LFS server enabled")
|
||||
}
|
||||
|
||||
var err error
|
||||
switch setting.Protocol {
|
||||
case setting.HTTP:
|
||||
if handleRedirector {
|
||||
NoHTTPRedirector()
|
||||
}
|
||||
err = runHTTP("tcp", listenAddr, "Web", m)
|
||||
case setting.HTTPS:
|
||||
if setting.EnableAcme {
|
||||
err = runACME(listenAddr, m)
|
||||
break
|
||||
} else {
|
||||
if handleRedirector {
|
||||
if setting.RedirectOtherPort {
|
||||
go runHTTPRedirector()
|
||||
} else {
|
||||
NoHTTPRedirector()
|
||||
}
|
||||
}
|
||||
err = runHTTPS("tcp", listenAddr, "Web", setting.CertFile, setting.KeyFile, m)
|
||||
}
|
||||
case setting.FCGI:
|
||||
if handleRedirector {
|
||||
NoHTTPRedirector()
|
||||
}
|
||||
err = runFCGI("tcp", listenAddr, "FCGI Web", m)
|
||||
case setting.HTTPUnix:
|
||||
if handleRedirector {
|
||||
NoHTTPRedirector()
|
||||
}
|
||||
err = runHTTP("unix", listenAddr, "Web", m)
|
||||
case setting.FCGIUnix:
|
||||
if handleRedirector {
|
||||
NoHTTPRedirector()
|
||||
}
|
||||
err = runFCGI("unix", listenAddr, "Web", m)
|
||||
default:
|
||||
log.Fatal("Invalid protocol: %s", setting.Protocol)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Critical("Failed to start server: %v", err)
|
||||
}
|
||||
log.Info("HTTP Listener: %s Closed", listenAddr)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/caddyserver/certmagic"
|
||||
)
|
||||
|
||||
func getCARoot(path string) (*x509.CertPool, error) {
|
||||
r, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block, _ := pem.Decode(r)
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("no PEM found in the file %s", path)
|
||||
}
|
||||
caRoot, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certPool := x509.NewCertPool()
|
||||
certPool.AddCert(caRoot)
|
||||
return certPool, nil
|
||||
}
|
||||
|
||||
func runACME(listenAddr string, m http.Handler) error {
|
||||
// If HTTP Challenge enabled, needs to be serving on port 80. For TLSALPN needs 443.
|
||||
// Due to docker port mapping this can't be checked programmatically
|
||||
// TODO: these are placeholders until we add options for each in settings with appropriate warning
|
||||
enableHTTPChallenge := true
|
||||
enableTLSALPNChallenge := true
|
||||
altHTTPPort := 0
|
||||
altTLSALPNPort := 0
|
||||
|
||||
if p, err := strconv.Atoi(setting.PortToRedirect); err == nil {
|
||||
altHTTPPort = p
|
||||
}
|
||||
if p, err := strconv.Atoi(setting.HTTPPort); err == nil {
|
||||
altTLSALPNPort = p
|
||||
}
|
||||
|
||||
magic := certmagic.NewDefault()
|
||||
magic.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory}
|
||||
// Try to use private CA root if provided, otherwise defaults to system's trust
|
||||
var certPool *x509.CertPool
|
||||
if setting.AcmeCARoot != "" {
|
||||
var err error
|
||||
certPool, err = getCARoot(setting.AcmeCARoot)
|
||||
if err != nil {
|
||||
log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err)
|
||||
}
|
||||
}
|
||||
myACME := certmagic.NewACMEIssuer(magic, certmagic.ACMEIssuer{
|
||||
CA: setting.AcmeURL,
|
||||
TrustedRoots: certPool,
|
||||
Email: setting.AcmeEmail,
|
||||
Agreed: setting.AcmeTOS,
|
||||
DisableHTTPChallenge: !enableHTTPChallenge,
|
||||
DisableTLSALPNChallenge: !enableTLSALPNChallenge,
|
||||
ListenHost: setting.HTTPAddr,
|
||||
AltTLSALPNPort: altTLSALPNPort,
|
||||
AltHTTPPort: altHTTPPort,
|
||||
})
|
||||
|
||||
magic.Issuers = []certmagic.Issuer{myACME}
|
||||
|
||||
// this obtains certificates or renews them if necessary
|
||||
err := magic.ManageSync(graceful.GetManager().HammerContext(), []string{setting.Domain})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tlsConfig := magic.TLSConfig()
|
||||
tlsConfig.NextProtos = append(tlsConfig.NextProtos, "h2")
|
||||
|
||||
if version := toTLSVersion(setting.SSLMinimumVersion); version != 0 {
|
||||
tlsConfig.MinVersion = version
|
||||
}
|
||||
if version := toTLSVersion(setting.SSLMaximumVersion); version != 0 {
|
||||
tlsConfig.MaxVersion = version
|
||||
}
|
||||
|
||||
// Set curve preferences
|
||||
if curves := toCurvePreferences(setting.SSLCurvePreferences); len(curves) > 0 {
|
||||
tlsConfig.CurvePreferences = curves
|
||||
}
|
||||
|
||||
// Set cipher suites
|
||||
if ciphers := toTLSCiphers(setting.SSLCipherSuites); len(ciphers) > 0 {
|
||||
tlsConfig.CipherSuites = ciphers
|
||||
}
|
||||
|
||||
if enableHTTPChallenge {
|
||||
go func() {
|
||||
_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), "Web: ACME HTTP challenge server", process.SystemProcessType, true)
|
||||
defer finished()
|
||||
|
||||
log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
|
||||
// all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
|
||||
err := runHTTP("tcp", setting.HTTPAddr+":"+setting.PortToRedirect, "Let's Encrypt HTTP Challenge", myACME.HTTPChallengeHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)))
|
||||
if err != nil {
|
||||
log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
return runHTTPSWithTLSConfig("tcp", listenAddr, "Web", tlsConfig, m)
|
||||
}
|
||||
|
||||
func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" && r.Method != "HEAD" {
|
||||
http.Error(w, "Use HTTPS", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Remove the trailing slash at the end of setting.AppURL, the request
|
||||
// URI always contains a leading slash, which would result in a double
|
||||
// slash
|
||||
target := strings.TrimSuffix(setting.AppURL, "/") + r.URL.RequestURI()
|
||||
http.Redirect(w, r, target, http.StatusTemporaryRedirect)
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2016 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/fcgi"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
func runHTTP(network, listenAddr, name string, m http.Handler) error {
|
||||
return graceful.HTTPListenAndServe(network, listenAddr, name, m)
|
||||
}
|
||||
|
||||
// NoHTTPRedirector tells our cleanup routine that we will not be using a fallback http redirector
|
||||
func NoHTTPRedirector() {
|
||||
graceful.GetManager().InformCleanup()
|
||||
}
|
||||
|
||||
// NoMainListener tells our cleanup routine that we will not be using a possibly provided listener
|
||||
// for our main HTTP/HTTPS service
|
||||
func NoMainListener() {
|
||||
graceful.GetManager().InformCleanup()
|
||||
}
|
||||
|
||||
// NoInstallListener tells our cleanup routine that we will not be using a possibly provided listener
|
||||
// for our install HTTP/HTTPS service
|
||||
func NoInstallListener() {
|
||||
graceful.GetManager().InformCleanup()
|
||||
}
|
||||
|
||||
func runFCGI(network, listenAddr, name string, m http.Handler) error {
|
||||
// This needs to handle stdin as fcgi point
|
||||
fcgiServer := graceful.NewServer(network, listenAddr, name)
|
||||
|
||||
err := fcgiServer.ListenAndServe(func(listener net.Listener) error {
|
||||
return fcgi.Serve(listener, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
if setting.AppSubURL != "" {
|
||||
req.URL.Path = strings.TrimPrefix(req.URL.Path, setting.AppSubURL)
|
||||
}
|
||||
m.ServeHTTP(resp, req)
|
||||
}))
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal("Failed to start FCGI main server: %v", err)
|
||||
}
|
||||
log.Info("FCGI Listener: %s Closed", listenAddr)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
var tlsVersionStringMap = map[string]uint16{
|
||||
"": tls.VersionTLS12, // Default to tls.VersionTLS12
|
||||
"tlsv1.0": tls.VersionTLS10,
|
||||
"tlsv1.1": tls.VersionTLS11,
|
||||
"tlsv1.2": tls.VersionTLS12,
|
||||
"tlsv1.3": tls.VersionTLS13,
|
||||
}
|
||||
|
||||
func toTLSVersion(version string) uint16 {
|
||||
tlsVersion, ok := tlsVersionStringMap[strings.TrimSpace(strings.ToLower(version))]
|
||||
if !ok {
|
||||
log.Warn("Unknown tls version: %s", version)
|
||||
return 0
|
||||
}
|
||||
return tlsVersion
|
||||
}
|
||||
|
||||
var curveStringMap = map[string]tls.CurveID{
|
||||
"x25519": tls.X25519,
|
||||
"p256": tls.CurveP256,
|
||||
"p384": tls.CurveP384,
|
||||
"p521": tls.CurveP521,
|
||||
}
|
||||
|
||||
func toCurvePreferences(preferences []string) []tls.CurveID {
|
||||
ids := make([]tls.CurveID, 0, len(preferences))
|
||||
for _, pref := range preferences {
|
||||
id, ok := curveStringMap[strings.TrimSpace(strings.ToLower(pref))]
|
||||
if !ok {
|
||||
log.Warn("Unknown curve: %s", pref)
|
||||
}
|
||||
if id != 0 {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
var cipherStringMap = map[string]uint16{
|
||||
"rsa_with_rc4_128_sha": tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||
"rsa_with_3des_ede_cbc_sha": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
"rsa_with_aes_128_cbc_sha": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
"rsa_with_aes_256_cbc_sha": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
"rsa_with_aes_128_cbc_sha256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
|
||||
"rsa_with_aes_128_gcm_sha256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
"rsa_with_aes_256_gcm_sha384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
"ecdhe_ecdsa_with_rc4_128_sha": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||
"ecdhe_ecdsa_with_aes_128_cbc_sha": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
"ecdhe_ecdsa_with_aes_256_cbc_sha": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
"ecdhe_rsa_with_rc4_128_sha": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
||||
"ecdhe_rsa_with_3des_ede_cbc_sha": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
"ecdhe_rsa_with_aes_128_cbc_sha": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
"ecdhe_rsa_with_aes_256_cbc_sha": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
"ecdhe_ecdsa_with_aes_128_cbc_sha256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||
"ecdhe_rsa_with_aes_128_cbc_sha256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||
"ecdhe_rsa_with_aes_128_gcm_sha256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
"ecdhe_ecdsa_with_aes_128_gcm_sha256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
"ecdhe_rsa_with_aes_256_gcm_sha384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
"ecdhe_ecdsa_with_aes_256_gcm_sha384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
"ecdhe_rsa_with_chacha20_poly1305_sha256": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||
"ecdhe_ecdsa_with_chacha20_poly1305_sha256": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||
"ecdhe_rsa_with_chacha20_poly1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
"ecdhe_ecdsa_with_chacha20_poly1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
||||
"aes_128_gcm_sha256": tls.TLS_AES_128_GCM_SHA256,
|
||||
"aes_256_gcm_sha384": tls.TLS_AES_256_GCM_SHA384,
|
||||
"chacha20_poly1305_sha256": tls.TLS_CHACHA20_POLY1305_SHA256,
|
||||
}
|
||||
|
||||
func toTLSCiphers(cipherStrings []string) []uint16 {
|
||||
ciphers := make([]uint16, 0, len(cipherStrings))
|
||||
for _, cipherString := range cipherStrings {
|
||||
cipher, ok := cipherStringMap[strings.TrimSpace(strings.ToLower(cipherString))]
|
||||
if !ok {
|
||||
log.Warn("Unknown cipher: %s", cipherString)
|
||||
}
|
||||
if cipher != 0 {
|
||||
ciphers = append(ciphers, cipher)
|
||||
}
|
||||
}
|
||||
|
||||
return ciphers
|
||||
}
|
||||
|
||||
// defaultCiphers uses hardware support to check if AES is specifically
|
||||
// supported by the CPU.
|
||||
//
|
||||
// If AES is supported AES ciphers will be preferred over ChaCha based ciphers
|
||||
// (This code is directly inspired by the certmagic code.)
|
||||
func defaultCiphers() []uint16 {
|
||||
if cpuid.CPU.Supports(cpuid.AESNI) {
|
||||
return defaultCiphersAESfirst
|
||||
}
|
||||
return defaultCiphersChaChaFirst
|
||||
}
|
||||
|
||||
var (
|
||||
defaultCiphersAES = []uint16{
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
}
|
||||
|
||||
defaultCiphersChaCha = []uint16{
|
||||
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
||||
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
}
|
||||
|
||||
defaultCiphersAESfirst = append(defaultCiphersAES, defaultCiphersChaCha...)
|
||||
defaultCiphersChaChaFirst = append(defaultCiphersChaCha, defaultCiphersAES...)
|
||||
)
|
||||
|
||||
// runHTTPs listens on the provided network address and then calls
|
||||
// Serve to handle requests on incoming TLS connections.
|
||||
//
|
||||
// Filenames containing a certificate and matching private key for the server must
|
||||
// be provided. If the certificate is signed by a certificate authority, the
|
||||
// certFile should be the concatenation of the server's certificate followed by the
|
||||
// CA's certificate.
|
||||
func runHTTPS(network, listenAddr, name, certFile, keyFile string, m http.Handler) error {
|
||||
tlsConfig := &tls.Config{}
|
||||
if tlsConfig.NextProtos == nil {
|
||||
tlsConfig.NextProtos = []string{"h2", "http/1.1"}
|
||||
}
|
||||
|
||||
if version := toTLSVersion(setting.SSLMinimumVersion); version != 0 {
|
||||
tlsConfig.MinVersion = version
|
||||
}
|
||||
if version := toTLSVersion(setting.SSLMaximumVersion); version != 0 {
|
||||
tlsConfig.MaxVersion = version
|
||||
}
|
||||
|
||||
// Set curve preferences
|
||||
tlsConfig.CurvePreferences = []tls.CurveID{
|
||||
tls.X25519,
|
||||
tls.CurveP256,
|
||||
}
|
||||
if curves := toCurvePreferences(setting.SSLCurvePreferences); len(curves) > 0 {
|
||||
tlsConfig.CurvePreferences = curves
|
||||
}
|
||||
|
||||
// Set cipher suites
|
||||
tlsConfig.CipherSuites = defaultCiphers()
|
||||
if ciphers := toTLSCiphers(setting.SSLCipherSuites); len(ciphers) > 0 {
|
||||
tlsConfig.CipherSuites = ciphers
|
||||
}
|
||||
|
||||
tlsConfig.Certificates = make([]tls.Certificate, 1)
|
||||
|
||||
certPEMBlock, err := os.ReadFile(certFile)
|
||||
if err != nil {
|
||||
log.Error("Failed to load https cert file %s for %s:%s: %v", certFile, network, listenAddr, err)
|
||||
return err
|
||||
}
|
||||
|
||||
keyPEMBlock, err := os.ReadFile(keyFile)
|
||||
if err != nil {
|
||||
log.Error("Failed to load https key file %s for %s:%s: %v", keyFile, network, listenAddr, err)
|
||||
return err
|
||||
}
|
||||
|
||||
tlsConfig.Certificates[0], err = tls.X509KeyPair(certPEMBlock, keyPEMBlock)
|
||||
if err != nil {
|
||||
log.Error("Failed to create certificate from cert file %s and key file %s for %s:%s: %v", certFile, keyFile, network, listenAddr, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, name, tlsConfig, m)
|
||||
}
|
||||
|
||||
func runHTTPSWithTLSConfig(network, listenAddr, name string, tlsConfig *tls.Config, m http.Handler) error {
|
||||
return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, name, tlsConfig, m)
|
||||
}
|
4
main.go
4
main.go
|
@ -10,6 +10,8 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/cmd"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
hat_cmd "code.gitlink.org.cn/Gitlink/gitea_hat.git/cmd"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
|
@ -40,7 +42,7 @@ func main() {
|
|||
arguments - which can alternatively be run by running the subcommand web.`
|
||||
app.Version = Version + formatBuiltWith()
|
||||
app.Commands = []cli.Command{
|
||||
cmd.CmdWeb,
|
||||
hat_cmd.CmdWeb,
|
||||
cmd.CmdServ,
|
||||
cmd.CmdHook,
|
||||
cmd.CmdDump,
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package hat
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/routers/api/v1/misc"
|
||||
"code.gitea.io/gitea/services/auth"
|
||||
"github.com/go-chi/cors"
|
||||
)
|
||||
|
||||
func Routers() *web.Route {
|
||||
m := web.NewRoute()
|
||||
|
||||
m.Use(securityHeaders())
|
||||
if setting.CORSConfig.Enabled {
|
||||
m.Use(cors.Handler(cors.Options{
|
||||
// Scheme: setting.CORSConfig.Scheme, // FIXME: the cors middleware needs scheme option
|
||||
AllowedOrigins: setting.CORSConfig.AllowDomain,
|
||||
// setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option
|
||||
AllowedMethods: setting.CORSConfig.Methods,
|
||||
AllowCredentials: setting.CORSConfig.AllowCredentials,
|
||||
AllowedHeaders: []string{"Authorization", "X-Gitea-OTP"},
|
||||
MaxAge: int(setting.CORSConfig.MaxAge.Seconds()),
|
||||
}))
|
||||
}
|
||||
m.Use(context.APIContexter())
|
||||
|
||||
group := buildAuthGroup()
|
||||
if err := group.Init(); err != nil {
|
||||
log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err)
|
||||
}
|
||||
|
||||
// Get user from session if logged in.
|
||||
m.Use(context.APIAuth(group))
|
||||
|
||||
m.Use(context.ToggleAPI(&context.ToggleOptions{
|
||||
SignInRequired: setting.Service.RequireSignInView,
|
||||
}))
|
||||
|
||||
m.Use(context.ToggleAPI(&context.ToggleOptions{
|
||||
SignInRequired: setting.Service.RequireSignInView,
|
||||
}))
|
||||
|
||||
m.Group("", func() {
|
||||
m.Get("/version", misc.Version)
|
||||
})
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func securityHeaders() func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
// CORB: https://www.chromium.org/Home/chromium-security/corb-for-developers
|
||||
// http://stackoverflow.com/a/3146618/244009
|
||||
resp.Header().Set("x-content-type-options", "nosniff")
|
||||
next.ServeHTTP(resp, req)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func buildAuthGroup() *auth.Group {
|
||||
group := auth.NewGroup(
|
||||
&auth.OAuth2{},
|
||||
&auth.HTTPSign{},
|
||||
&auth.Basic{}, // FIXME: this should be removed once we don't allow basic auth in API
|
||||
)
|
||||
if setting.Service.EnableReverseProxyAuth {
|
||||
group.Add(&auth.ReverseProxy{})
|
||||
}
|
||||
|
||||
return group
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
func TagNameSet(ctx *context.APIContext) {
|
||||
// swagger:operation GET /repos/{owner}/{repo}/tag_name_set repository repoTagNameSet
|
||||
// ---
|
||||
// summary: List a repository's tag name***
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: owner
|
||||
// in: path
|
||||
// description: owner of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: repo
|
||||
// in: path
|
||||
// description: name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: name
|
||||
// in: query
|
||||
// description: name of the tag
|
||||
// type: string
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/BranchNameSet"
|
||||
|
||||
searchName := ctx.Params("name")
|
||||
|
||||
tags, err := ctx.Repo.GitRepo.GetTags(0, 0)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetTags", err)
|
||||
return
|
||||
}
|
||||
|
||||
if searchName == "" {
|
||||
ctx.JSON(http.StatusOK, tags)
|
||||
} else {
|
||||
var tagNameSet []string
|
||||
for _, tag := range tags {
|
||||
|
||||
log.Info("tag is \n", tag)
|
||||
if strings.Contains(tag, searchName) {
|
||||
tagNameSet = append(tagNameSet, tag)
|
||||
}
|
||||
}
|
||||
ctx.JSON(http.StatusOK, tagNameSet)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package routers
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
api_hat "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat"
|
||||
)
|
||||
|
||||
func InitHatRouters(e *web.Route) *web.Route {
|
||||
|
||||
e.Mount("/api/hat", api_hat.Routers())
|
||||
return e
|
||||
}
|
Loading…
Reference in New Issue