Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82b23ef638 | ||
|
|
d970ec35b7 | ||
|
|
e2872e786e | ||
|
|
f81e35d960 | ||
|
|
672fb860ea | ||
|
|
8081c83de4 | ||
|
|
f379d0e54a | ||
|
|
ffb6bd72ef | ||
|
|
488ef9de54 | ||
|
|
34349d4b48 | ||
|
|
2197d82957 | ||
|
|
20ece60a72 | ||
|
|
33e584b447 |
5
.github/workflows/build-test.yml
vendored
5
.github/workflows/build-test.yml
vendored
@@ -1,12 +1,10 @@
|
|||||||
name: "Build & Test"
|
name: Run Tests
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches-ignore:
|
branches-ignore:
|
||||||
- 'master'
|
- 'master'
|
||||||
- 'release/**'
|
- 'release/**'
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
@@ -32,6 +30,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GOOS: ${{ matrix.goos }}
|
GOOS: ${{ matrix.goos }}
|
||||||
GOARCH: ${{ matrix.goarch }}
|
GOARCH: ${{ matrix.goarch }}
|
||||||
|
CGO_ENABLED: 0
|
||||||
run: |
|
run: |
|
||||||
go build -v -ldflags="-s -w -X github.com/pterodactyl/wings/system.Version=dev-${GIT_COMMIT:0:7}" -o build/wings_${{ matrix.goos }}_${{ matrix.goarch }} wings.go
|
go build -v -ldflags="-s -w -X github.com/pterodactyl/wings/system.Version=dev-${GIT_COMMIT:0:7}" -o build/wings_${{ matrix.goos }}_${{ matrix.goarch }} wings.go
|
||||||
|
|
||||||
|
|||||||
12
.github/workflows/codeql-analysis.yml
vendored
12
.github/workflows/codeql-analysis.yml
vendored
@@ -1,16 +1,11 @@
|
|||||||
name: "Code scanning - action"
|
name: CodeQL Scanning
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
branches:
|
||||||
|
- 'develop'
|
||||||
pull_request:
|
pull_request:
|
||||||
schedule:
|
|
||||||
- cron: '0 21 * * 6'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
CodeQL-Build:
|
CodeQL-Build:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -18,7 +13,6 @@ jobs:
|
|||||||
# We must fetch at least the immediate parents so that if this is
|
# We must fetch at least the immediate parents so that if this is
|
||||||
# a pull request then we can checkout the head.
|
# a pull request then we can checkout the head.
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
|
|
||||||
# If this run was triggered by a pull request event, then checkout
|
# If this run was triggered by a pull request event, then checkout
|
||||||
# the head of the pull request instead of the merge commit.
|
# the head of the pull request instead of the merge commit.
|
||||||
- run: git checkout HEAD^2
|
- run: git checkout HEAD^2
|
||||||
|
|||||||
47
.github/workflows/docker.yml
vendored
Normal file
47
.github/workflows/docker.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
name: Publish Docker Image
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'develop'
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
jobs:
|
||||||
|
push_to_registry:
|
||||||
|
name: Push Image to GitHub Packages
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Always run against a tag, even if the commit into the tag has [docker skip]
|
||||||
|
# within the commit message.
|
||||||
|
if: "!contains(github.ref, 'develop') || (!contains(github.event.head_commit.message, 'skip docker') && !contains(github.event.head_commit.message, 'docker skip'))"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: crazy-max/ghaction-docker-meta@v1
|
||||||
|
id: docker_meta
|
||||||
|
with:
|
||||||
|
images: ghcr.io/pterodactyl/wings
|
||||||
|
- uses: docker/setup-qemu-action@v1
|
||||||
|
- uses: docker/setup-buildx-action@v1
|
||||||
|
- uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
- name: Release Production Build
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
if: "!contains(github.ref, 'develop')"
|
||||||
|
env:
|
||||||
|
REF: ${{ github.ref }}
|
||||||
|
with:
|
||||||
|
push: true
|
||||||
|
build-args: |
|
||||||
|
VERSION=${REF:11}
|
||||||
|
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||||
|
- name: Release Development Build
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
if: "contains(github.ref, 'develop')"
|
||||||
|
with:
|
||||||
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
build-args: |
|
||||||
|
VERSION=dev-${GIT_COMMIT:0:7}
|
||||||
|
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||||
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -1,10 +1,8 @@
|
|||||||
name: "Release"
|
name: Create Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- 'v*'
|
- 'v*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
@@ -20,9 +18,9 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
REF: ${{ github.ref }}
|
REF: ${{ github.ref }}
|
||||||
run: |
|
run: |
|
||||||
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -X github.com/pterodactyl/wings/system.Version=${REF:11}" -o build/wings_linux_amd64 -v wings.go
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -X github.com/pterodactyl/wings/system.Version=${REF:11}" -o build/wings_linux_amd64 -v wings.go
|
||||||
GOOS=linux GOARCH=arm64 go build -ldflags="-s -w -X github.com/pterodactyl/wings/system.Version=${REF:11}" -o build/wings_linux_arm64 -v wings.go
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="-s -w -X github.com/pterodactyl/wings/system.Version=${REF:11}" -o build/wings_linux_arm64 -v wings.go
|
||||||
GOOS=linux GOARCH=arm go build -ldflags="-s -w -X github.com/pterodactyl/wings/system.Version=${REF:11}" -o build/wings_linux_arm -v wings.go
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags="-s -w -X github.com/pterodactyl/wings/system.Version=${REF:11}" -o build/wings_linux_arm -v wings.go
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: go test ./...
|
run: go test ./...
|
||||||
|
|||||||
17
CHANGELOG.md
17
CHANGELOG.md
@@ -1,5 +1,22 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.1.2
|
||||||
|
### Fixed
|
||||||
|
* Fixes binaries built as part of the release process not being usable in MUSL based environments (such as our Docker images).
|
||||||
|
* Fixes server states being incorrectly set back to offline when a server is started after a system restart.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* Improved logic for cleaning `allowed_mount` paths for consistency.
|
||||||
|
* Certain context cancelation deadline errors are no longer wrong reported at an error level (since they're expected).
|
||||||
|
* Very minor micro-optimizations for some string handling with server console output.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* Added a hidden option to disable all disk checking for servers by setting the `disk_check_interval` to `0` in the config file.
|
||||||
|
|
||||||
|
## v1.1.1
|
||||||
|
### Fixed
|
||||||
|
* Fixes certain files returning invalid data in the request due to a bad header set after sending data down the line.
|
||||||
|
|
||||||
## v1.1.0
|
## v1.1.0
|
||||||
This release **requires** `Panel@1.1.0` or later to run due to API changes.
|
This release **requires** `Panel@1.1.0` or later to run due to API changes.
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
# ----------------------------------
|
|
||||||
# Pterodactyl Panel Dockerfile
|
|
||||||
# ----------------------------------
|
|
||||||
|
|
||||||
FROM golang:1.15-alpine
|
FROM golang:1.15-alpine
|
||||||
|
ARG VERSION="develop"
|
||||||
COPY . /go/wings/
|
COPY . /go/wings/
|
||||||
WORKDIR /go/wings/
|
WORKDIR /go/wings/
|
||||||
RUN apk add --no-cache upx \
|
RUN apk add --no-cache upx \
|
||||||
&& go build -ldflags="-s -w" \
|
&& CGO_ENABLED=0 go build -ldflags="-s -w -X github.com/pterodactyl/wings/system.Version=${VERSION}" \
|
||||||
&& upx --brute wings
|
&& upx wings
|
||||||
|
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
COPY --from=0 /go/wings/wings /usr/bin/
|
COPY --from=0 /go/wings/wings /usr/bin/
|
||||||
|
|||||||
11
cmd/root.go
11
cmd/root.go
@@ -250,13 +250,12 @@ func rootCmdRun(*cobra.Command, []string) {
|
|||||||
if err := s.Environment.Attach(); err != nil {
|
if err := s.Environment.Attach(); err != nil {
|
||||||
s.Log().WithField("error", errors.WithStackIf(err)).Warn("failed to attach to running server environment")
|
s.Log().WithField("error", errors.WithStackIf(err)).Warn("failed to attach to running server environment")
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
return
|
// At this point we've determined that the server should indeed be in an offline state, so we'll
|
||||||
}
|
// make a call to set that state just to ensure we don't ever accidentally end up with some invalid
|
||||||
|
// state being tracked.
|
||||||
// Addresses potentially invalid data in the stored file that can cause Wings to lose
|
|
||||||
// track of what the actual server state is.
|
|
||||||
s.Environment.SetState(environment.ProcessOfflineState)
|
s.Environment.SetState(environment.ProcessOfflineState)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,12 +47,6 @@ type Configuration struct {
|
|||||||
System SystemConfiguration `json:"system" yaml:"system"`
|
System SystemConfiguration `json:"system" yaml:"system"`
|
||||||
Docker DockerConfiguration `json:"docker" yaml:"docker"`
|
Docker DockerConfiguration `json:"docker" yaml:"docker"`
|
||||||
|
|
||||||
// The amount of time in seconds that should elapse between disk usage checks
|
|
||||||
// run by the daemon. Setting a higher number can result in better IO performance
|
|
||||||
// at an increased risk of a malicious user creating a process that goes over
|
|
||||||
// the assigned disk limits.
|
|
||||||
DiskCheckTimeout int `yaml:"disk_check_timeout"`
|
|
||||||
|
|
||||||
// Defines internal throttling configurations for server processes to prevent
|
// Defines internal throttling configurations for server processes to prevent
|
||||||
// someone from running an endless loop that spams data to logs.
|
// someone from running an endless loop that spams data to logs.
|
||||||
Throttles ConsoleThrottles
|
Throttles ConsoleThrottles
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ type SystemConfiguration struct {
|
|||||||
// considered stale and a re-check should occur. DANGER: setting this value too low can seriously
|
// considered stale and a re-check should occur. DANGER: setting this value too low can seriously
|
||||||
// impact system performance and cause massive I/O bottlenecks and high CPU usage for the Wings
|
// impact system performance and cause massive I/O bottlenecks and high CPU usage for the Wings
|
||||||
// process.
|
// process.
|
||||||
|
//
|
||||||
|
// Set to 0 to disable disk checking entirely. This will always return 0 for the disk space used
|
||||||
|
// by a server and should only be set in extreme scenarios where performance is critical and
|
||||||
|
// disk usage is not a concern.
|
||||||
DiskCheckInterval int64 `default:"150" yaml:"disk_check_interval"`
|
DiskCheckInterval int64 `default:"150" yaml:"disk_check_interval"`
|
||||||
|
|
||||||
// Determines if Wings should detect a server that stops with a normal exit code of
|
// Determines if Wings should detect a server that stops with a normal exit code of
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
version: '3.5'
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
daemon:
|
wings:
|
||||||
build: .
|
image: ghcr.io/pterodactyl/wings:latest
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
- daemon0
|
- wings0
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
- "2022:2022"
|
- "2022:2022"
|
||||||
tty: true
|
tty: true
|
||||||
environment:
|
environment:
|
||||||
- "DEBUG=false"
|
TZ: UTC
|
||||||
- "TZ=UTC" # change to the three letter timezone of your choosing
|
DEBUG: false
|
||||||
volumes:
|
volumes:
|
||||||
- "/var/run/docker.sock:/var/run/docker.sock"
|
- "/var/run/docker.sock:/var/run/docker.sock"
|
||||||
- "/var/lib/docker/containers/:/var/lib/docker/containers/"
|
- "/var/lib/docker/containers/:/var/lib/docker/containers/"
|
||||||
@@ -19,17 +19,16 @@ services:
|
|||||||
- "/var/lib/pterodactyl/:/var/lib/pterodactyl/"
|
- "/var/lib/pterodactyl/:/var/lib/pterodactyl/"
|
||||||
- "/var/log/pterodactyl/:/var/log/pterodactyl/"
|
- "/var/log/pterodactyl/:/var/log/pterodactyl/"
|
||||||
- "/tmp/pterodactyl/:/tmp/pterodactyl/"
|
- "/tmp/pterodactyl/:/tmp/pterodactyl/"
|
||||||
## you may need /srv/daemon-data if you are upgrading from an old daemon
|
# you may need /srv/daemon-data if you are upgrading from an old daemon
|
||||||
## - "/srv/daemon-data/:/srv/daemon-data/"
|
#- "/srv/daemon-data/:/srv/daemon-data/"
|
||||||
## Required for ssl if you user let's encrypt. uncomment to use.
|
# Required for ssl if you user let's encrypt. uncomment to use.
|
||||||
## - "/etc/letsencrypt/:/etc/letsencrypt/"
|
#- "/etc/letsencrypt/:/etc/letsencrypt/"
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
daemon0:
|
wings0:
|
||||||
name: daemon0
|
name: wings0
|
||||||
driver: bridge
|
driver: bridge
|
||||||
ipam:
|
ipam:
|
||||||
config:
|
config:
|
||||||
- subnet: "172.21.0.0/16"
|
- subnet: "172.21.0.0/16"
|
||||||
driver_opts:
|
driver_opts:
|
||||||
com.docker.network.bridge.name: daemon0
|
com.docker.network.bridge.name: wings0
|
||||||
@@ -70,7 +70,12 @@ func (e *Environment) Attach() error {
|
|||||||
// indicates that the container is no longer running.
|
// indicates that the container is no longer running.
|
||||||
go func(ctx context.Context) {
|
go func(ctx context.Context) {
|
||||||
if err := e.pollResources(ctx); err != nil {
|
if err := e.pollResources(ctx); err != nil {
|
||||||
log.WithField("environment_id", e.Id).WithField("error", errors.WithStackIf(err)).Error("error during environment resource polling")
|
l := log.WithField("environment_id", e.Id)
|
||||||
|
if !errors.Is(err, context.Canceled) {
|
||||||
|
l.WithField("error", errors.WithStackIf(err)).Error("error during environment resource polling")
|
||||||
|
} else {
|
||||||
|
l.Warn("stopping server resource polling: context canceled")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}(ctx)
|
}(ctx)
|
||||||
|
|
||||||
@@ -291,9 +296,20 @@ func (e *Environment) followOutput() error {
|
|||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
|
|
||||||
r := bufio.NewReader(reader)
|
r := bufio.NewReader(reader)
|
||||||
|
|
||||||
|
// Micro-optimization to create these replacements one time when this routine
|
||||||
|
// fires up, rather than on every line that is executed.
|
||||||
|
cr := []byte(" \r")
|
||||||
|
crr := []byte("\r\n")
|
||||||
|
|
||||||
|
|
||||||
|
// Avoid constantly re-allocating memory when we're flooding lines through this
|
||||||
|
// function by using the same buffer for the duration of the call and just truncating
|
||||||
|
// the value back to 0 every loop.
|
||||||
|
var str strings.Builder
|
||||||
ParentLoop:
|
ParentLoop:
|
||||||
for {
|
for {
|
||||||
var b bytes.Buffer
|
str.Reset()
|
||||||
var line []byte
|
var line []byte
|
||||||
var isPrefix bool
|
var isPrefix bool
|
||||||
|
|
||||||
@@ -305,7 +321,7 @@ func (e *Environment) followOutput() error {
|
|||||||
// in line with that it thinks is the terminal size. Those returns break a lot of output handling,
|
// in line with that it thinks is the terminal size. Those returns break a lot of output handling,
|
||||||
// so we'll just replace them with proper new-lines and then split it later and send each line as
|
// so we'll just replace them with proper new-lines and then split it later and send each line as
|
||||||
// its own event in the response.
|
// its own event in the response.
|
||||||
b.Write(bytes.ReplaceAll(line, []byte(" \r"), []byte("\r\n")))
|
str.Write(bytes.Replace(line, cr, crr, -1))
|
||||||
|
|
||||||
// Finish this loop and begin outputting the line if there is no prefix (the line fit into
|
// Finish this loop and begin outputting the line if there is no prefix (the line fit into
|
||||||
// the default buffer), or if we hit the end of the line.
|
// the default buffer), or if we hit the end of the line.
|
||||||
@@ -322,7 +338,7 @@ func (e *Environment) followOutput() error {
|
|||||||
|
|
||||||
// Publish the line for this loop. Break on new-line characters so every line is sent as a single
|
// Publish the line for this loop. Break on new-line characters so every line is sent as a single
|
||||||
// output event, otherwise you get funky handling in the browser console.
|
// output event, otherwise you get funky handling in the browser console.
|
||||||
for _, line := range strings.Split(b.String(), "\r\n") {
|
for _, line := range strings.Split(str.String(), "\r\n") {
|
||||||
e.Events().Publish(environment.ConsoleOutputEvent, line)
|
e.Events().Publish(environment.ConsoleOutputEvent, line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ func (e *Environment) WaitForStop(seconds uint, terminate bool) error {
|
|||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
if ctxErr := ctx.Err(); ctxErr != nil {
|
if ctxErr := ctx.Err(); ctxErr != nil {
|
||||||
if terminate {
|
if terminate {
|
||||||
log.WithField("container_id", e.Id).Debug("server did not stop in time, executing process termination")
|
log.WithField("container_id", e.Id).Info("server did not stop in time, executing process termination")
|
||||||
|
|
||||||
return errors.WithStackIf(e.Terminate(os.Kill))
|
return errors.WithStackIf(e.Terminate(os.Kill))
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,12 @@ func (e *Environment) WaitForStop(seconds uint, terminate bool) error {
|
|||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if terminate {
|
if terminate {
|
||||||
log.WithField("container_id", e.Id).WithField("error", errors.WithStackIf(err)).Warn("error while waiting for container stop, attempting process termination")
|
l := log.WithField("container_id", e.Id)
|
||||||
|
if errors.Is(err, context.DeadlineExceeded) {
|
||||||
|
l.Warn("deadline exceeded for container stop; terminating process")
|
||||||
|
} else {
|
||||||
|
l.WithField("error", errors.WithStackIf(err)).Warn("error while waiting for container stop; terminating process")
|
||||||
|
}
|
||||||
|
|
||||||
return errors.WithStackIf(e.Terminate(os.Kill))
|
return errors.WithStackIf(e.Terminate(os.Kill))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,15 +15,14 @@ import (
|
|||||||
// Attach to the instance and then automatically emit an event whenever the resource usage for the
|
// Attach to the instance and then automatically emit an event whenever the resource usage for the
|
||||||
// server process changes.
|
// server process changes.
|
||||||
func (e *Environment) pollResources(ctx context.Context) error {
|
func (e *Environment) pollResources(ctx context.Context) error {
|
||||||
l := log.WithField("container_id", e.Id)
|
|
||||||
|
|
||||||
l.Debug("starting resource polling for container")
|
|
||||||
defer l.Debug("stopped resource polling for container")
|
|
||||||
|
|
||||||
if e.st.Load() == environment.ProcessOfflineState {
|
if e.st.Load() == environment.ProcessOfflineState {
|
||||||
return errors.New("cannot enable resource polling on a stopped server")
|
return errors.New("cannot enable resource polling on a stopped server")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
l := log.WithField("container_id", e.Id)
|
||||||
|
l.Debug("starting resource polling for container")
|
||||||
|
defer l.Debug("stopped resource polling for container")
|
||||||
|
|
||||||
stats, err := e.client.ContainerStats(context.Background(), e.Id, true)
|
stats, err := e.client.ContainerStats(context.Background(), e.Id, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithStackIf(err)
|
return errors.WithStackIf(err)
|
||||||
@@ -35,7 +34,7 @@ func (e *Environment) pollResources(ctx context.Context) error {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ctx.Err()
|
return errors.WithStackIf(ctx.Err())
|
||||||
default:
|
default:
|
||||||
var v *types.StatsJSON
|
var v *types.StatsJSON
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,6 @@ func getServerFileContents(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.Filesystem().Readfile(p, c.Writer); err != nil {
|
|
||||||
TrackedServerError(err, s).AbortFilesystemError(c)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
c.Header("X-Mime-Type", st.Mimetype)
|
c.Header("X-Mime-Type", st.Mimetype)
|
||||||
c.Header("Content-Length", strconv.Itoa(int(st.Info.Size())))
|
c.Header("Content-Length", strconv.Itoa(int(st.Info.Size())))
|
||||||
|
|
||||||
@@ -48,6 +44,19 @@ func getServerFileContents(c *gin.Context) {
|
|||||||
c.Header("Content-Disposition", "attachment; filename="+st.Info.Name())
|
c.Header("Content-Disposition", "attachment; filename="+st.Info.Name())
|
||||||
c.Header("Content-Type", "application/octet-stream")
|
c.Header("Content-Type", "application/octet-stream")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(dane): should probably come up with a different approach here. If an error is encountered
|
||||||
|
// by this Readfile call you'll end up causing a (recovered) panic in the program because so many
|
||||||
|
// headers have already been set. We should probably add a RawReadfile that just returns the file
|
||||||
|
// to be read and then we can stream from that safely without error.
|
||||||
|
//
|
||||||
|
// Until that becomes a problem though I'm just going to leave this how it is. The panic is recovered
|
||||||
|
// and a normal 500 error is returned to the client to my knowledge. It is also very unlikely to
|
||||||
|
// happen since we're doing so much before this point that would normally throw an error if there
|
||||||
|
// was a problem with the file.
|
||||||
|
if err := s.Filesystem().Readfile(p, c.Writer); err != nil {
|
||||||
|
TrackedServerError(err, s).AbortFilesystemError(c)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,11 @@ func (fs *Filesystem) CachedUsage() int64 {
|
|||||||
// This is primarily to avoid a bunch of I/O operations from piling up on the server, especially on servers
|
// This is primarily to avoid a bunch of I/O operations from piling up on the server, especially on servers
|
||||||
// with a large amount of files.
|
// with a large amount of files.
|
||||||
func (fs *Filesystem) DiskUsage(allowStaleValue bool) (int64, error) {
|
func (fs *Filesystem) DiskUsage(allowStaleValue bool) (int64, error) {
|
||||||
|
// A disk check interval of 0 means this functionality is completely disabled.
|
||||||
|
if fs.diskCheckInterval == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
if !fs.lastLookupTime.Get().After(time.Now().Add(time.Second * fs.diskCheckInterval * -1)) {
|
if !fs.lastLookupTime.Get().After(time.Now().Add(time.Second * fs.diskCheckInterval * -1)) {
|
||||||
// If we are now allowing a stale response go ahead and perform the lookup and return the fresh
|
// If we are now allowing a stale response go ahead and perform the lookup and return the fresh
|
||||||
// value. This is a blocking operation to the calling process.
|
// value. This is a blocking operation to the calling process.
|
||||||
|
|||||||
@@ -49,7 +49,9 @@ func (s *Server) customMounts() []environment.Mount {
|
|||||||
|
|
||||||
mounted := false
|
mounted := false
|
||||||
for _, allowed := range config.Get().AllowedMounts {
|
for _, allowed := range config.Get().AllowedMounts {
|
||||||
if !strings.HasPrefix(source, allowed) {
|
// Check if the source path is included in the allowed mounts list.
|
||||||
|
// filepath.Clean will strip all trailing slashes (unless the path is a root directory).
|
||||||
|
if !strings.HasPrefix(source, filepath.Clean(allowed)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user