mirror of
https://codeberg.org/Codeberg/pages-server.git
synced 2025-04-24 22:06:57 +00:00
Merge branch 'main' into issue-163
This commit is contained in:
commit
54bff210e0
7 changed files with 36 additions and 8 deletions
13
README.md
13
README.md
|
@ -1,5 +1,11 @@
|
||||||
# Codeberg Pages
|
# Codeberg Pages
|
||||||
|
|
||||||
|
[](https://opensource.org/license/eupl-1-2/)
|
||||||
|
[](https://ci.codeberg.org/Codeberg/pages-server)
|
||||||
|
<a href="https://matrix.to/#/#gitea-pages-server:matrix.org" title="Join the Matrix room at https://matrix.to/#/#gitea-pages-server:matrix.org">
|
||||||
|
<img src="https://img.shields.io/matrix/gitea-pages-server:matrix.org?label=matrix">
|
||||||
|
</a>
|
||||||
|
|
||||||
Gitea lacks the ability to host static pages from Git.
|
Gitea lacks the ability to host static pages from Git.
|
||||||
The Codeberg Pages Server addresses this lack by implementing a standalone service
|
The Codeberg Pages Server addresses this lack by implementing a standalone service
|
||||||
that connects to Gitea via API.
|
that connects to Gitea via API.
|
||||||
|
@ -8,6 +14,9 @@ It is suitable to be deployed by other Gitea instances, too, to offer static pag
|
||||||
**End user documentation** can mainly be found at the [Wiki](https://codeberg.org/Codeberg/pages-server/wiki/Overview)
|
**End user documentation** can mainly be found at the [Wiki](https://codeberg.org/Codeberg/pages-server/wiki/Overview)
|
||||||
and the [Codeberg Documentation](https://docs.codeberg.org/codeberg-pages/).
|
and the [Codeberg Documentation](https://docs.codeberg.org/codeberg-pages/).
|
||||||
|
|
||||||
|
|
||||||
|
<a href="https://codeberg.org/Codeberg/pages-server"> <img src="https://codeberg.org/Codeberg/GetItOnCodeberg/raw/branch/main/get-it-on-blue-on-white.svg" alt="Get It On Codeberg" width="250"/> <a/>
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
This is the new Codeberg Pages server, a solution for serving static pages from Gitea repositories.
|
This is the new Codeberg Pages server, a solution for serving static pages from Gitea repositories.
|
||||||
|
@ -29,6 +38,10 @@ record that points to your repo (just like the CNAME record):
|
||||||
|
|
||||||
Certificates are generated, updated and cleaned up automatically via Let's Encrypt through a TLS challenge.
|
Certificates are generated, updated and cleaned up automatically via Let's Encrypt through a TLS challenge.
|
||||||
|
|
||||||
|
## Chat for admins & devs
|
||||||
|
|
||||||
|
[matrix: #gitea-pages-server:matrix.org](https://matrix.to/#/#gitea-pages-server:matrix.org)
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
**Warning: Some Caveats Apply**
|
**Warning: Some Caveats Apply**
|
||||||
|
|
|
@ -64,7 +64,7 @@ func TestGetContent(t *testing.T) {
|
||||||
assert.True(t, getSize(resp.Body) > 100)
|
assert.True(t, getSize(resp.Body) > 100)
|
||||||
assert.Len(t, resp.Header.Get("ETag"), 44)
|
assert.Len(t, resp.Header.Get("ETag"), 44)
|
||||||
|
|
||||||
// TODO: test get of non cachable content (content size > fileCacheSizeLimit)
|
// TODO: test get of non cacheable content (content size > fileCacheSizeLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCustomDomain(t *testing.T) {
|
func TestCustomDomain(t *testing.T) {
|
||||||
|
@ -124,7 +124,7 @@ func TestRawCustomDomain(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRawIndex(t *testing.T) {
|
func TestRawIndex(t *testing.T) {
|
||||||
log.Println("=== TestRawCustomDomain ===")
|
log.Println("=== TestRawIndex ===")
|
||||||
// test raw domain response for index.html
|
// test raw domain response for index.html
|
||||||
resp, err := getTestHTTPSClient().Get("https://raw.localhost.mock.directory:4430/cb_pages_tests/raw-test/@branch-test/index.html") // need cb_pages_tests fork
|
resp, err := getTestHTTPSClient().Get("https://raw.localhost.mock.directory:4430/cb_pages_tests/raw-test/@branch-test/index.html") // need cb_pages_tests fork
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -154,6 +154,7 @@ func TestGetNotFound(t *testing.T) {
|
||||||
func TestFollowSymlink(t *testing.T) {
|
func TestFollowSymlink(t *testing.T) {
|
||||||
log.Printf("=== TestFollowSymlink ===\n")
|
log.Printf("=== TestFollowSymlink ===\n")
|
||||||
|
|
||||||
|
// file symlink
|
||||||
resp, err := getTestHTTPSClient().Get("https://cb_pages_tests.localhost.mock.directory:4430/tests_for_pages-server/@main/link")
|
resp, err := getTestHTTPSClient().Get("https://cb_pages_tests.localhost.mock.directory:4430/tests_for_pages-server/@main/link")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if !assert.NotNil(t, resp) {
|
if !assert.NotNil(t, resp) {
|
||||||
|
@ -165,6 +166,16 @@ func TestFollowSymlink(t *testing.T) {
|
||||||
body := getBytes(resp.Body)
|
body := getBytes(resp.Body)
|
||||||
assert.EqualValues(t, 4, len(body))
|
assert.EqualValues(t, 4, len(body))
|
||||||
assert.EqualValues(t, "abc\n", string(body))
|
assert.EqualValues(t, "abc\n", string(body))
|
||||||
|
|
||||||
|
// relative file links (../index.html file in this case)
|
||||||
|
resp, err = getTestHTTPSClient().Get("https://cb_pages_tests.localhost.mock.directory:4430/tests_for_pages-server/@main/dir_aim/some/")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.NotNil(t, resp) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
assert.EqualValues(t, http.StatusOK, resp.StatusCode)
|
||||||
|
assert.EqualValues(t, "text/html; charset=utf-8", resp.Header.Get("Content-Type"))
|
||||||
|
assert.EqualValues(t, "an index\n", string(getBytes(resp.Body)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLFSSupport(t *testing.T) {
|
func TestLFSSupport(t *testing.T) {
|
||||||
|
|
|
@ -23,7 +23,7 @@ func TestMain(m *testing.M) {
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
serverCancel()
|
serverCancel()
|
||||||
log.Println("=== TestMain: Server STOPED ===")
|
log.Println("=== TestMain: Server STOPPED ===")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
|
|
|
@ -89,7 +89,7 @@ func NewAcmeClient(acmeAccountConf, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID,
|
||||||
acmeClientRequestLimit: equalizer.NewTokenBucket(5, 1*time.Second),
|
acmeClientRequestLimit: equalizer.NewTokenBucket(5, 1*time.Second),
|
||||||
// rate limit is 5 / hour https://letsencrypt.org/docs/failed-validation-limit/
|
// rate limit is 5 / hour https://letsencrypt.org/docs/failed-validation-limit/
|
||||||
acmeClientFailLimit: equalizer.NewTokenBucket(5, 1*time.Hour),
|
acmeClientFailLimit: equalizer.NewTokenBucket(5, 1*time.Hour),
|
||||||
// checkUserLimit() use this to rate als per user
|
// checkUserLimit() use this to rate also per user
|
||||||
acmeClientCertificateLimitPerUser: map[string]*equalizer.TokenBucket{},
|
acmeClientCertificateLimitPerUser: map[string]*equalizer.TokenBucket{},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ func NewXormDB(dbType, dbConn string) (CertDB, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := e.Sync2(new(Cert)); err != nil {
|
if err := e.Sync2(new(Cert)); err != nil {
|
||||||
return nil, fmt.Errorf("cound not sync db model :%w", err)
|
return nil, fmt.Errorf("could not sync db model :%w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &xDB{
|
return &xDB{
|
||||||
|
@ -64,7 +64,7 @@ func (x xDB) Put(domain string, cert *certificate.Resource) error {
|
||||||
}
|
}
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
|
|
||||||
if exist, _ := sess.ID(c.Domain).Exist(); exist {
|
if exist, _ := sess.ID(c.Domain).Exist(new(Cert)); exist {
|
||||||
if _, err := sess.ID(c.Domain).Update(c); err != nil {
|
if _, err := sess.ID(c.Domain).Update(c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ func TestSanitizeWildcardCerts(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// update existing cert
|
// update existing cert
|
||||||
assert.Error(t, certDB.Put(".wildcard.de", &certificate.Resource{
|
assert.NoError(t, certDB.Put(".wildcard.de", &certificate.Resource{
|
||||||
Domain: "*.wildcard.de",
|
Domain: "*.wildcard.de",
|
||||||
Certificate: localhost_mock_directory_certificate,
|
Certificate: localhost_mock_directory_certificate,
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -112,7 +112,7 @@ func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource str
|
||||||
if cache, ok := client.responseCache.Get(cacheKey); ok {
|
if cache, ok := client.responseCache.Get(cacheKey); ok {
|
||||||
cache := cache.(FileResponse)
|
cache := cache.(FileResponse)
|
||||||
cachedHeader, cachedStatusCode := cache.createHttpResponse(cacheKey)
|
cachedHeader, cachedStatusCode := cache.createHttpResponse(cacheKey)
|
||||||
// TODO: check against some timestamp missmatch?!?
|
// TODO: check against some timestamp mismatch?!?
|
||||||
if cache.Exists {
|
if cache.Exists {
|
||||||
if cache.IsSymlink {
|
if cache.IsSymlink {
|
||||||
linkDest := string(cache.Body)
|
linkDest := string(cache.Body)
|
||||||
|
@ -145,6 +145,10 @@ func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource str
|
||||||
}
|
}
|
||||||
linkDest := strings.TrimSpace(string(linkDestBytes))
|
linkDest := strings.TrimSpace(string(linkDestBytes))
|
||||||
|
|
||||||
|
// handle relative links
|
||||||
|
// we first remove the link from the path, and make a relative join (resolve parent paths like "/../" too)
|
||||||
|
linkDest = path.Join(path.Dir(resource), linkDest)
|
||||||
|
|
||||||
// we store symlink not content to reduce duplicates in cache
|
// we store symlink not content to reduce duplicates in cache
|
||||||
if err := client.responseCache.Set(cacheKey, FileResponse{
|
if err := client.responseCache.Set(cacheKey, FileResponse{
|
||||||
Exists: true,
|
Exists: true,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue