208 lines
5.0 KiB
Go
208 lines
5.0 KiB
Go
package main
|
|
|
|
import (
|
|
"embed"
|
|
"encoding/json"
|
|
"fmt"
|
|
"html/template"
|
|
"io"
|
|
"mime"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/joho/godotenv"
|
|
)
|
|
|
|
//go:embed pages
|
|
var embeddedFiles embed.FS
|
|
|
|
type transport struct {
|
|
apiKey string
|
|
underlyingTransport http.RoundTripper
|
|
}
|
|
|
|
func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
if t.apiKey != "" {
|
|
req.Header.Add("Authorization", "token "+t.apiKey)
|
|
}
|
|
return t.underlyingTransport.RoundTrip(req)
|
|
}
|
|
|
|
func main() {
|
|
godotenv.Load()
|
|
// if os.Args[len(os.Args)-1] == "gencrt" {
|
|
// GenCerts()
|
|
// os.Exit(0)
|
|
// }
|
|
// if _, err := os.Stat("./certs/cert.crt"); err != nil {
|
|
// fmt.Println("Not found cert file")
|
|
// GenCerts()
|
|
// }
|
|
// if _, err := os.Stat("./certs/priv.key"); err != nil {
|
|
// fmt.Println("Not fount cert key file")
|
|
// GenCerts()
|
|
// }
|
|
//certFile, _ := os.ReadFile("./certs/cert.crt")
|
|
//block, _ := pem.Decode(certFile)
|
|
//if block == nil {
|
|
// fmt.Println("invalid certificate")
|
|
// GenCerts()
|
|
// }
|
|
// cert, _ := x509.ParseCertificate(block.Bytes)
|
|
// certExpired := time.Now().After(cert.NotAfter)
|
|
// if certExpired {
|
|
// GenCerts()
|
|
// }
|
|
rootDomain, exists := os.LookupEnv("ROOT_DOMAIN")
|
|
if !exists {
|
|
rootDomain = "localhost"
|
|
}
|
|
giteaUrl, exists := os.LookupEnv("GITEA_URL")
|
|
if !exists {
|
|
giteaUrl = "https://codeberg.org"
|
|
}
|
|
defaultRef, exists := os.LookupEnv("DEFAULT_REF")
|
|
if !exists {
|
|
defaultRef = "pages"
|
|
}
|
|
indexFile, exists := os.LookupEnv("INDEX_FILE")
|
|
if !exists {
|
|
indexFile = "index.html"
|
|
}
|
|
directoryIndexStr := os.Getenv("DIRECTORY_INDEX")
|
|
fmt.Println(rootDomain, giteaUrl)
|
|
directoryIndex := false
|
|
if directoryIndexStr == "true" {
|
|
directoryIndex = true
|
|
}
|
|
defaultUser := os.Getenv("DEFAULT_USER")
|
|
servePort, exists := os.LookupEnv("SERVE_PORT")
|
|
if !exists {
|
|
servePort = "8080"
|
|
}
|
|
giteaToken := os.Getenv("GITEA_TOKEN")
|
|
|
|
gitea := http.Client{Transport: &transport{underlyingTransport: http.DefaultTransport, apiKey: giteaToken}}
|
|
|
|
r := gin.Default()
|
|
|
|
templ := template.Must(template.New("").ParseFS(embeddedFiles, "pages/*"))
|
|
r.SetHTMLTemplate(templ)
|
|
|
|
r.GET("/*path", func(ctx *gin.Context) {
|
|
path := ctx.Params.ByName("path")
|
|
|
|
rawHost := ctx.Request.Host
|
|
if !strings.HasSuffix(rawHost, rootDomain) {
|
|
ctx.HTML(404, "error.html", gin.H{
|
|
"error_code": "400",
|
|
"error_message": "invalid root domain",
|
|
})
|
|
return
|
|
}
|
|
hostPrefix := strings.TrimSuffix(rawHost, rootDomain)
|
|
host := strings.Split(hostPrefix, ".")
|
|
|
|
var owner string
|
|
switch len(host) - 1 {
|
|
case 0:
|
|
ctx.HTML(200, "index.html", gin.H{
|
|
"root_domain": rootDomain,
|
|
})
|
|
return
|
|
case 2:
|
|
owner = host[1]
|
|
case 1:
|
|
if defaultUser == "" {
|
|
goto godefault
|
|
}
|
|
owner = defaultUser
|
|
break
|
|
godefault:
|
|
fallthrough
|
|
default:
|
|
ctx.HTML(400, "index.html", gin.H{
|
|
"root_domain": rootDomain,
|
|
})
|
|
return
|
|
}
|
|
|
|
repo := host[0]
|
|
|
|
contentPath := giteaUrl + "/api/v1/repos/" + owner + "/" + repo + "/contents/" + path + "?ref=" + defaultRef
|
|
apiPath := giteaUrl + "/api/v1/repos/" + owner + "/" + repo + "/raw" + path
|
|
resp, err := gitea.Get(apiPath + "?ref=" + defaultRef)
|
|
if err != nil {
|
|
ctx.AbortWithError(500, err)
|
|
}
|
|
body, _ := io.ReadAll(resp.Body)
|
|
var message struct {
|
|
Message string
|
|
}
|
|
if resp.StatusCode == 200 {
|
|
// if file found
|
|
ct := mime.TypeByExtension(filepath.Ext(path))
|
|
ctx.Data(200, ct, body)
|
|
} else {
|
|
// if file not found, and get err message
|
|
json.Unmarshal(body, &message)
|
|
|
|
if message.Message != "getBlobForEntry" && path != "/" {
|
|
ctx.HTML(404, "error.html", gin.H{
|
|
"error_code": "404",
|
|
"error_message": "file not found",
|
|
})
|
|
return
|
|
}
|
|
// check is index file (from env) exists
|
|
indexPath := apiPath + "/" + indexFile + "?ref=" + defaultRef
|
|
resp, _ := gitea.Get(indexPath)
|
|
if resp.StatusCode == 200 {
|
|
// index file exist
|
|
body, _ := io.ReadAll(resp.Body)
|
|
ctx.Data(200, "text/html", body)
|
|
return
|
|
} else {
|
|
// else this is directory
|
|
resp, _ := gitea.Get(contentPath)
|
|
body, _ := io.ReadAll(resp.Body)
|
|
var dir []struct {
|
|
Name string
|
|
Path string
|
|
}
|
|
json.Unmarshal(body, &dir)
|
|
if len(dir) == 0 {
|
|
// zero files, empty or non-existent repo
|
|
ctx.HTML(404, "error.html", gin.H{
|
|
"error_code": "404",
|
|
"error_message": "pages for repository not found",
|
|
})
|
|
return
|
|
}
|
|
if !directoryIndex {
|
|
// if directory index disabled
|
|
ctx.HTML(401, "error.html", gin.H{
|
|
"error_code": "401",
|
|
"error_message": "directory index disabled",
|
|
})
|
|
return
|
|
}
|
|
var html string
|
|
html += "<h1>Index of " + path + "</h1>"
|
|
html += "<a href=\"" + filepath.Dir(path) + "\">Parrent directory</a><br/>"
|
|
for _, file := range dir {
|
|
html += "<a href=\"/" + file.Path + "\">" + file.Name + "</a><br/>"
|
|
}
|
|
ctx.Data(200, "text/html", []byte(html))
|
|
return
|
|
}
|
|
}
|
|
|
|
//ctx.JSON(200, gin.H{"host": host, "path": path})
|
|
})
|
|
r.Run(":" + servePort)
|
|
}
|