mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-07 23:00:55 +03:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4445834fd3 | ||
|
|
19a619ff65 | ||
|
|
66a538dc9c | ||
|
|
1a6863f4b1 | ||
|
|
fbd9919afa | ||
|
|
eec8bc73f4 | ||
|
|
5720d40fee | ||
|
|
38e0cba675 | ||
|
|
4c5a0d663e | ||
|
|
093df15fac | ||
|
|
957430e675 |
34
.github/workflows/development.yml
vendored
34
.github/workflows/development.yml
vendored
@@ -86,7 +86,7 @@ jobs:
|
||||
with:
|
||||
dest: cross
|
||||
prefix: sftpgo
|
||||
targets: linux/arm64
|
||||
targets: linux/arm64,linux/ppc64le
|
||||
v: true
|
||||
x: false
|
||||
race: false
|
||||
@@ -108,7 +108,12 @@ jobs:
|
||||
./sftpgo gen completion zsh > output/zsh_completion/_sftpgo
|
||||
./sftpgo gen man -d output/man/man1
|
||||
gzip output/man/man1/*
|
||||
cp cross/sftpgo-linux-arm64 output/ || :
|
||||
|
||||
- name: Copy cross compiled Linux binaries
|
||||
if: ${{ matrix.upload-coverage && startsWith(matrix.os, 'ubuntu-') }}
|
||||
run: |
|
||||
cp cross/sftpgo-linux-arm64 output/
|
||||
cp cross/sftpgo-linux-ppc64le output/
|
||||
|
||||
- name: Prepare build artifact for Windows
|
||||
if: startsWith(matrix.os, 'windows-')
|
||||
@@ -132,6 +137,7 @@ jobs:
|
||||
if: ${{ matrix.upload-coverage && startsWith(matrix.os, 'ubuntu-') }}
|
||||
run: |
|
||||
cp -r pkgs pkgs_arm64
|
||||
cp -r pkgs pkgs_ppc64le
|
||||
cd pkgs
|
||||
./build.sh
|
||||
cd ..
|
||||
@@ -140,6 +146,12 @@ jobs:
|
||||
cp cross/sftpgo${BIN_SUFFIX} .
|
||||
cd pkgs_arm64
|
||||
./build.sh
|
||||
cd ..
|
||||
export NFPM_ARCH=ppc64le
|
||||
export BIN_SUFFIX=-linux-ppc64le
|
||||
cp cross/sftpgo${BIN_SUFFIX} .
|
||||
cd pkgs_ppc64le
|
||||
./build.sh
|
||||
PKG_VERSION=$(cat dist/version)
|
||||
echo "::set-output name=pkg-version::${PKG_VERSION}"
|
||||
|
||||
@@ -162,14 +174,28 @@ jobs:
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: sftpgo-${{ steps.build_linux_pkgs.outputs.pkg-version }}-arm64-deb
|
||||
path: pkgs/dist/deb/*
|
||||
path: pkgs_arm64/dist/deb/*
|
||||
|
||||
- name: Upload RPM Package arm64
|
||||
if: ${{ matrix.upload-coverage && startsWith(matrix.os, 'ubuntu-') }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: sftpgo-${{ steps.build_linux_pkgs.outputs.pkg-version }}-arm64-rpm
|
||||
path: pkgs/dist/rpm/*
|
||||
path: pkgs_arm64/dist/rpm/*
|
||||
|
||||
- name: Upload Debian Package ppc64le
|
||||
if: ${{ matrix.upload-coverage && startsWith(matrix.os, 'ubuntu-') }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: sftpgo-${{ steps.build_linux_pkgs.outputs.pkg-version }}-ppc64le-deb
|
||||
path: pkgs_ppc64le/dist/deb/*
|
||||
|
||||
- name: Upload RPM Package ppc64le
|
||||
if: ${{ matrix.upload-coverage && startsWith(matrix.os, 'ubuntu-') }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: sftpgo-${{ steps.build_linux_pkgs.outputs.pkg-version }}-ppc64le-rpm
|
||||
path: pkgs_ppc64le/dist/rpm/*
|
||||
|
||||
test-postgresql-mysql:
|
||||
name: Test with PostgreSQL/MySQL
|
||||
|
||||
84
.github/workflows/docker.yml
vendored
84
.github/workflows/docker.yml
vendored
@@ -21,9 +21,6 @@ jobs:
|
||||
docker_pkg:
|
||||
- debian
|
||||
- alpine
|
||||
docker_image:
|
||||
- drakkan/sftpgo
|
||||
- ghcr.io/drakkan/sftpgo
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
@@ -40,7 +37,8 @@ jobs:
|
||||
id: info
|
||||
run: |
|
||||
VERSION=noop
|
||||
DOCKERFILE=Dockerfile
|
||||
DOCKERFILE_SLIM=Dockerfile
|
||||
DOCKERFILE=Dockerfile.full
|
||||
MINOR=""
|
||||
MAJOR=""
|
||||
if [ "${{ github.event_name }}" = "schedule" ]; then
|
||||
@@ -59,45 +57,72 @@ jobs:
|
||||
MINOR=${VERSION%.*}
|
||||
MAJOR=${MINOR%.*}
|
||||
fi
|
||||
VERSION_SLIM="${VERSION}-slim"
|
||||
if [[ $DOCKER_PKG == alpine ]]; then
|
||||
VERSION="${VERSION}-alpine"
|
||||
DOCKERFILE=Dockerfile.alpine
|
||||
VERSION_SLIM="${VERSION}-slim"
|
||||
DOCKERFILE_SLIM=Dockerfile.alpine
|
||||
DOCKERFILE=Dockerfile.full.alpine
|
||||
fi
|
||||
|
||||
DOCKER_IMAGES=("drakkan/sftpgo" "ghcr.io/drakkan/sftpgo")
|
||||
TAGS="${DOCKER_IMAGES[0]}:${VERSION}"
|
||||
TAGS_SLIM="${DOCKER_IMAGES[0]}:${VERSION_SLIM}"
|
||||
BASE_IMAGE="${TAGS_SLIM}"
|
||||
|
||||
for DOCKER_IMAGE in ${DOCKER_IMAGES[@]}; do
|
||||
if [[ ${DOCKER_IMAGE} != ${DOCKER_IMAGES[0]} ]]; then
|
||||
TAGS="${TAGS},${DOCKER_IMAGE}:${VERSION}"
|
||||
TAGS_SLIM="${TAGS_SLIM},${DOCKER_IMAGE}:${VERSION_SLIM}"
|
||||
fi
|
||||
TAGS="${DOCKER_IMAGE}:${VERSION}"
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
if [[ $DOCKER_PKG == debian ]]; then
|
||||
if [[ -n $MAJOR && -n $MINOR ]]; then
|
||||
TAGS="$TAGS,${DOCKER_IMAGE}:${MINOR},${DOCKER_IMAGE}:${MAJOR}"
|
||||
TAGS="${TAGS},${DOCKER_IMAGE}:${MINOR},${DOCKER_IMAGE}:${MAJOR}"
|
||||
TAGS_SLIM="${TAGS_SLIM},${DOCKER_IMAGE}:${MINOR}-slim,${DOCKER_IMAGE}:${MAJOR}-slim"
|
||||
fi
|
||||
TAGS="$TAGS,${DOCKER_IMAGE}:latest"
|
||||
TAGS="${TAGS},${DOCKER_IMAGE}:latest"
|
||||
TAGS_SLIM="${TAGS_SLIM},${DOCKER_IMAGE}:slim"
|
||||
else
|
||||
if [[ -n $MAJOR && -n $MINOR ]]; then
|
||||
TAGS="$TAGS,${DOCKER_IMAGE}:${MINOR}-alpine,${DOCKER_IMAGE}:${MAJOR}-alpine"
|
||||
TAGS="${TAGS},${DOCKER_IMAGE}:${MINOR}-alpine,${DOCKER_IMAGE}:${MAJOR}-alpine"
|
||||
TAGS_SLIM="${TAGS_SLIM},${DOCKER_IMAGE}:${MINOR}-alpine-slim,${DOCKER_IMAGE}:${MAJOR}-alpine-slim"
|
||||
fi
|
||||
TAGS="$TAGS,${DOCKER_IMAGE}:alpine"
|
||||
TAGS="${TAGS},${DOCKER_IMAGE}:alpine"
|
||||
TAGS_SLIM="${TAGS_SLIM},${DOCKER_IMAGE}:alpine-slim"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo ::set-output name=dockerfile::${DOCKERFILE}
|
||||
echo ::set-output name=dockerfile-slim::${DOCKERFILE_SLIM}
|
||||
echo ::set-output name=version::${VERSION}
|
||||
echo ::set-output name=version-slim::${VERSION_SLIM}
|
||||
echo ::set-output name=tags::${TAGS}
|
||||
echo ::set-output name=tags-slim::${TAGS_SLIM}
|
||||
echo ::set-output name=base-image::${BASE_IMAGE}
|
||||
echo ::set-output name=created::$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||
echo ::set-output name=sha::${GITHUB_SHA::8}
|
||||
env:
|
||||
DOCKER_PKG: ${{ matrix.docker_pkg }}
|
||||
DOCKER_IMAGE: ${{ matrix.docker_image }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
- name: Set up builder slim
|
||||
uses: docker/setup-buildx-action@v1
|
||||
id: builder-slim
|
||||
|
||||
- name: Set up builder full
|
||||
uses: docker/setup-buildx-action@v1
|
||||
id: builder-full
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
if: ${{ github.event_name != 'pull_request' && matrix.docker_image == 'drakkan/sftpgo' }}
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
@@ -105,15 +130,16 @@ jobs:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.CR_PAT }}
|
||||
if: ${{ github.event_name != 'pull_request' && matrix.docker_image == 'ghcr.io/drakkan/sftpgo' }}
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
|
||||
- name: Build and push
|
||||
- name: Build and push slim
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
file: ./${{ steps.info.outputs.dockerfile }}
|
||||
builder: ${{ steps.builder-slim.outputs.name }}
|
||||
file: ./${{ steps.info.outputs.dockerfile-slim }}
|
||||
platforms: linux/amd64,linux/arm64,linux/ppc64le
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.info.outputs.tags }}
|
||||
tags: ${{ steps.info.outputs.tags-slim }}
|
||||
build-args: |
|
||||
COMMIT_SHA=${{ steps.info.outputs.sha }}
|
||||
labels: |
|
||||
@@ -121,7 +147,29 @@ jobs:
|
||||
org.opencontainers.image.description=Fully featured and highly configurable SFTP server with optional FTP/S and WebDAV support
|
||||
org.opencontainers.image.url=${{ fromJson(steps.repo.outputs.result).html_url }}
|
||||
org.opencontainers.image.documentation=${{ fromJson(steps.repo.outputs.result).html_url }}/blob/${{ github.sha }}/docker/README.md
|
||||
org.opencontainers.image.source=${{ fromJson(steps.repo.outputs.result).clone_url }}
|
||||
org.opencontainers.image.source=${{ fromJson(steps.repo.outputs.result).html_url }}
|
||||
org.opencontainers.image.version=${{ steps.info.outputs.version }}
|
||||
org.opencontainers.image.created=${{ steps.info.outputs.created }}
|
||||
org.opencontainers.image.revision=${{ github.sha }}
|
||||
org.opencontainers.image.licenses=${{ fromJson(steps.repo.outputs.result).license.spdx_id }}
|
||||
|
||||
- name: Build and push full
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
builder: ${{ steps.builder-full.outputs.name }}
|
||||
file: ./${{ steps.info.outputs.dockerfile }}
|
||||
platforms: linux/amd64,linux/arm64,linux/ppc64le
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.info.outputs.tags }}
|
||||
build-args: |
|
||||
COMMIT_SHA=${{ steps.info.outputs.sha }}
|
||||
BASE_IMAGE=${{ steps.info.outputs.base-image }}
|
||||
labels: |
|
||||
org.opencontainers.image.title=SFTPGo
|
||||
org.opencontainers.image.description=Fully featured and highly configurable SFTP server with optional FTP/S and WebDAV support
|
||||
org.opencontainers.image.url=${{ fromJson(steps.repo.outputs.result).html_url }}
|
||||
org.opencontainers.image.documentation=${{ fromJson(steps.repo.outputs.result).html_url }}/blob/${{ github.sha }}/docker/README.md
|
||||
org.opencontainers.image.source=${{ fromJson(steps.repo.outputs.result).html_url }}
|
||||
org.opencontainers.image.version=${{ steps.info.outputs.version }}
|
||||
org.opencontainers.image.created=${{ steps.info.outputs.created }}
|
||||
org.opencontainers.image.revision=${{ github.sha }}
|
||||
|
||||
71
.github/workflows/release.yml
vendored
71
.github/workflows/release.yml
vendored
@@ -5,7 +5,7 @@ on:
|
||||
tags: 'v*'
|
||||
|
||||
env:
|
||||
GO_VERSION: 1.15.4
|
||||
GO_VERSION: 1.15.5
|
||||
|
||||
jobs:
|
||||
create-release:
|
||||
@@ -160,7 +160,7 @@ jobs:
|
||||
with:
|
||||
dest: cross
|
||||
prefix: sftpgo
|
||||
targets: linux/arm64
|
||||
targets: linux/arm64,linux/ppc64le
|
||||
v: true
|
||||
x: false
|
||||
race: false
|
||||
@@ -191,7 +191,12 @@ jobs:
|
||||
./sftpgo gen man -d output/man/man1
|
||||
gzip output/man/man1/*
|
||||
cp examples/rest-api-cli/sftpgo_api_cli output/examples/rest-api-cli/
|
||||
if [ $OS == 'linux' ]
|
||||
then
|
||||
cp -r output output_arm64
|
||||
cp -r output output_ppc64le
|
||||
cp -r output output_all
|
||||
fi
|
||||
cd output
|
||||
tar cJvf sftpgo_${SFTPGO_VERSION}_${OS}_x86_64.tar.xz *
|
||||
cd ..
|
||||
@@ -201,6 +206,16 @@ jobs:
|
||||
cd output_arm64
|
||||
tar cJvf sftpgo_${SFTPGO_VERSION}_${OS}_arm64.tar.xz *
|
||||
cd ..
|
||||
cp cross/sftpgo-linux-ppc64le output_ppc64le/sftpgo
|
||||
cd output_ppc64le
|
||||
tar cJvf sftpgo_${SFTPGO_VERSION}_${OS}_ppc64le.tar.xz *
|
||||
cd ..
|
||||
mkdir output_all/{arm64,ppc64le}
|
||||
cp cross/sftpgo-linux-arm64 output_all/arm64/sftpgo
|
||||
cp cross/sftpgo-linux-ppc64le output_all/ppc64le/sftpgo
|
||||
cd output_all
|
||||
tar cJvf sftpgo_${SFTPGO_VERSION}_${OS}_bundle.tar.xz *
|
||||
cd ..
|
||||
fi
|
||||
env:
|
||||
SFTPGO_VERSION: ${{ steps.get_version.outputs.VERSION }}
|
||||
@@ -211,6 +226,7 @@ jobs:
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
cp -r pkgs pkgs_arm64
|
||||
cp -r pkgs pkgs_ppc64le
|
||||
cd pkgs
|
||||
./build.sh
|
||||
cd ..
|
||||
@@ -219,6 +235,13 @@ jobs:
|
||||
cp cross/sftpgo${BIN_SUFFIX} .
|
||||
cd pkgs_arm64
|
||||
./build.sh
|
||||
cd ..
|
||||
export NFPM_ARCH=ppc64le
|
||||
export BIN_SUFFIX=-linux-ppc64le
|
||||
cp cross/sftpgo${BIN_SUFFIX} .
|
||||
cd pkgs_ppc64le
|
||||
./build.sh
|
||||
cd ..
|
||||
PKG_VERSION=${SFTPGO_VERSION:1}
|
||||
echo "::set-output name=pkg-version::${PKG_VERSION}"
|
||||
env:
|
||||
@@ -294,6 +317,28 @@ jobs:
|
||||
asset_name: sftpgo_${{ steps.get_version.outputs.VERSION }}_${{ steps.get_os_name.outputs.OS }}_arm64.tar.xz
|
||||
asset_content_type: application/x-xz
|
||||
|
||||
- name: Upload Linux/ppc64le Release
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.upload_url.outputs.url }}
|
||||
asset_path: ./output_ppc64le/sftpgo_${{ steps.get_version.outputs.VERSION }}_${{ steps.get_os_name.outputs.OS }}_ppc64le.tar.xz
|
||||
asset_name: sftpgo_${{ steps.get_version.outputs.VERSION }}_${{ steps.get_os_name.outputs.OS }}_ppc64le.tar.xz
|
||||
asset_content_type: application/x-xz
|
||||
|
||||
- name: Upload Linux Bundle Release
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.upload_url.outputs.url }}
|
||||
asset_path: ./output_all/sftpgo_${{ steps.get_version.outputs.VERSION }}_${{ steps.get_os_name.outputs.OS }}_bundle.tar.xz
|
||||
asset_name: sftpgo_${{ steps.get_version.outputs.VERSION }}_${{ steps.get_os_name.outputs.OS }}_bundle.tar.xz
|
||||
asset_content_type: application/x-xz
|
||||
|
||||
- name: Upload Windows Release
|
||||
if: startsWith(matrix.os, 'windows-')
|
||||
uses: actions/upload-release-asset@v1
|
||||
@@ -359,3 +404,25 @@ jobs:
|
||||
asset_path: ./pkgs_arm64/dist/rpm/sftpgo-${{ steps.build_linux_pkgs.outputs.pkg-version }}-1.aarch64.rpm
|
||||
asset_name: sftpgo-${{ steps.build_linux_pkgs.outputs.pkg-version }}-1.aarch64.rpm
|
||||
asset_content_type: application/x-rpm
|
||||
|
||||
- name: Upload Debian Package ppc64le
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.upload_url.outputs.url }}
|
||||
asset_path: ./pkgs_ppc64le/dist/deb/sftpgo_${{ steps.build_linux_pkgs.outputs.pkg-version }}-1_ppc64el.deb
|
||||
asset_name: sftpgo_${{ steps.build_linux_pkgs.outputs.pkg-version }}-1_ppc64el.deb
|
||||
asset_content_type: application/vnd.debian.binary-package
|
||||
|
||||
- name: Upload RPM Package ppc64le
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.upload_url.outputs.url }}
|
||||
asset_path: ./pkgs_ppc64le/dist/rpm/sftpgo-${{ steps.build_linux_pkgs.outputs.pkg-version }}-1.ppc64le.rpm
|
||||
asset_name: sftpgo-${{ steps.build_linux_pkgs.outputs.pkg-version }}-1.ppc64le.rpm
|
||||
asset_content_type: application/x-rpm
|
||||
|
||||
13
Dockerfile
13
Dockerfile
@@ -25,9 +25,7 @@ RUN set -xe && \
|
||||
|
||||
FROM debian:buster-slim
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y ca-certificates mime-support && apt-get clean
|
||||
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y ca-certificates mime-support && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN mkdir -p /etc/sftpgo /var/lib/sftpgo /usr/share/sftpgo /srv/sftpgo
|
||||
|
||||
@@ -36,9 +34,6 @@ RUN groupadd --system -g 1000 sftpgo && \
|
||||
--home-dir /var/lib/sftpgo --shell /usr/sbin/nologin \
|
||||
--comment "SFTPGo user" --uid 1000 sftpgo
|
||||
|
||||
# Install some optional packages used by SFTPGo features
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y git rsync && apt-get clean
|
||||
|
||||
COPY --from=builder /workspace/sftpgo.json /etc/sftpgo/sftpgo.json
|
||||
COPY --from=builder /workspace/templates /usr/share/sftpgo/templates
|
||||
COPY --from=builder /workspace/static /usr/share/sftpgo/static
|
||||
@@ -55,11 +50,11 @@ RUN sed -i "s|\"users_base_dir\": \"\",|\"users_base_dir\": \"/srv/sftpgo/data\"
|
||||
sed -i "s|\"backups\"|\"/srv/sftpgo/backups\"|" /etc/sftpgo/sftpgo.json && \
|
||||
sed -i "s|\"bind_address\": \"127.0.0.1\",|\"bind_address\": \"\",|" /etc/sftpgo/sftpgo.json
|
||||
|
||||
COPY ./docker/scripts/entrypoint.sh /docker-entrypoint.sh
|
||||
|
||||
RUN chown -R sftpgo:sftpgo /etc/sftpgo && chown sftpgo:sftpgo /var/lib/sftpgo /srv/sftpgo
|
||||
|
||||
WORKDIR /var/lib/sftpgo
|
||||
USER 1000:1000
|
||||
|
||||
VOLUME [ "/var/lib/sftpgo", "/srv/sftpgo" ]
|
||||
|
||||
CMD sftpgo serve
|
||||
CMD ["sftpgo", "serve"]
|
||||
|
||||
@@ -28,9 +28,7 @@ RUN set -xe && \
|
||||
|
||||
FROM alpine:3.12
|
||||
|
||||
RUN apk add --update --no-cache ca-certificates tzdata bash mailcap
|
||||
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
RUN apk add --update --no-cache ca-certificates tzdata mailcap
|
||||
|
||||
# set up nsswitch.conf for Go's "netgo" implementation
|
||||
# https://github.com/gliderlabs/docker-alpine/issues/367#issuecomment-424546457
|
||||
@@ -39,10 +37,7 @@ RUN test ! -e /etc/nsswitch.conf && echo 'hosts: files dns' > /etc/nsswitch.conf
|
||||
RUN mkdir -p /etc/sftpgo /var/lib/sftpgo /usr/share/sftpgo /srv/sftpgo
|
||||
|
||||
RUN addgroup -g 1000 -S sftpgo && \
|
||||
adduser -u 1000 -h /var/lib/sftpgo -s /sbin/nologin -G sftpgo -S -D -H sftpgo
|
||||
|
||||
# Install some optional packages used by SFTPGo features
|
||||
RUN apk add --update --no-cache rsync git
|
||||
adduser -u 1000 -h /var/lib/sftpgo -s /sbin/nologin -G sftpgo -S -D -H -g "SFTPGo user" sftpgo
|
||||
|
||||
COPY --from=builder /workspace/sftpgo.json /etc/sftpgo/sftpgo.json
|
||||
COPY --from=builder /workspace/templates /usr/share/sftpgo/templates
|
||||
@@ -65,6 +60,4 @@ RUN chown -R sftpgo:sftpgo /etc/sftpgo && chown sftpgo:sftpgo /var/lib/sftpgo /s
|
||||
WORKDIR /var/lib/sftpgo
|
||||
USER 1000:1000
|
||||
|
||||
VOLUME [ "/var/lib/sftpgo", "/srv/sftpgo" ]
|
||||
|
||||
CMD sftpgo serve
|
||||
CMD ["sftpgo", "serve"]
|
||||
|
||||
10
Dockerfile.full
Normal file
10
Dockerfile.full
Normal file
@@ -0,0 +1,10 @@
|
||||
ARG BASE_IMAGE
|
||||
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
USER root
|
||||
|
||||
# Install some optional packages used by SFTPGo features
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y git rsync && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
USER 1000:1000
|
||||
10
Dockerfile.full.alpine
Normal file
10
Dockerfile.full.alpine
Normal file
@@ -0,0 +1,10 @@
|
||||
ARG BASE_IMAGE
|
||||
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
USER root
|
||||
|
||||
# Install some optional packages used by SFTPGo features
|
||||
RUN apk add --update --no-cache rsync git
|
||||
|
||||
USER 1000:1000
|
||||
@@ -4,6 +4,7 @@
|
||||
[](https://codecov.io/gh/drakkan/sftpgo/branch/master)
|
||||
[](https://goreportcard.com/report/github.com/drakkan/sftpgo)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||
[](https://hub.docker.com/r/drakkan/sftpgo)
|
||||
[](https://github.com/avelino/awesome-go)
|
||||
|
||||
Fully featured and highly configurable SFTP server with optional FTP/S and WebDAV support, written in Go.
|
||||
|
||||
@@ -223,6 +223,8 @@ type Configuration struct {
|
||||
Actions ProtocolActions `json:"actions" mapstructure:"actions"`
|
||||
// SetstatMode 0 means "normal mode": requests for changing permissions and owner/group are executed.
|
||||
// 1 means "ignore mode": requests for changing permissions and owner/group are silently ignored.
|
||||
// 2 means "ignore mode for cloud fs": requests for changing permissions and owner/group/time are
|
||||
// silently ignored for cloud based filesystem such as S3, GCS, Azure Blob
|
||||
SetstatMode int `json:"setstat_mode" mapstructure:"setstat_mode"`
|
||||
// Support for HAProxy PROXY protocol.
|
||||
// If you are running SFTPGo behind a proxy server such as HAProxy, AWS ELB or NGNIX, you can enable
|
||||
|
||||
@@ -448,29 +448,39 @@ func (c *BaseConnection) DoStat(fsPath string, mode int) (os.FileInfo, error) {
|
||||
return c.Fs.Stat(c.getRealFsPath(fsPath))
|
||||
}
|
||||
|
||||
// SetStat set StatAttributes for the specified fsPath
|
||||
func (c *BaseConnection) SetStat(fsPath, virtualPath string, attributes *StatAttributes) error {
|
||||
func (c *BaseConnection) ignoreSetStat() bool {
|
||||
if Config.SetstatMode == 1 {
|
||||
return nil
|
||||
return true
|
||||
}
|
||||
if Config.SetstatMode == 2 && !vfs.IsLocalOsFs(c.Fs) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
pathForPerms := c.getPathForSetStatPerms(fsPath, virtualPath)
|
||||
|
||||
if attributes.Flags&StatAttrPerms != 0 {
|
||||
func (c *BaseConnection) handleChmod(fsPath, pathForPerms string, attributes *StatAttributes) error {
|
||||
if !c.User.HasPerm(dataprovider.PermChmod, pathForPerms) {
|
||||
return c.GetPermissionDeniedError()
|
||||
}
|
||||
if c.ignoreSetStat() {
|
||||
return nil
|
||||
}
|
||||
if err := c.Fs.Chmod(c.getRealFsPath(fsPath), attributes.Mode); err != nil {
|
||||
c.Log(logger.LevelWarn, "failed to chmod path %#v, mode: %v, err: %+v", fsPath, attributes.Mode.String(), err)
|
||||
return c.GetFsError(err)
|
||||
}
|
||||
logger.CommandLog(chmodLogSender, fsPath, "", c.User.Username, attributes.Mode.String(), c.ID, c.protocol,
|
||||
-1, -1, "", "", "", -1)
|
||||
return nil
|
||||
}
|
||||
|
||||
if attributes.Flags&StatAttrUIDGID != 0 {
|
||||
func (c *BaseConnection) handleChown(fsPath, pathForPerms string, attributes *StatAttributes) error {
|
||||
if !c.User.HasPerm(dataprovider.PermChown, pathForPerms) {
|
||||
return c.GetPermissionDeniedError()
|
||||
}
|
||||
if c.ignoreSetStat() {
|
||||
return nil
|
||||
}
|
||||
if err := c.Fs.Chown(c.getRealFsPath(fsPath), attributes.UID, attributes.GID); err != nil {
|
||||
c.Log(logger.LevelWarn, "failed to chown path %#v, uid: %v, gid: %v, err: %+v", fsPath, attributes.UID,
|
||||
attributes.GID, err)
|
||||
@@ -478,13 +488,16 @@ func (c *BaseConnection) SetStat(fsPath, virtualPath string, attributes *StatAtt
|
||||
}
|
||||
logger.CommandLog(chownLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, attributes.UID, attributes.GID,
|
||||
"", "", "", -1)
|
||||
return nil
|
||||
}
|
||||
|
||||
if attributes.Flags&StatAttrTimes != 0 {
|
||||
func (c *BaseConnection) handleChtimes(fsPath, pathForPerms string, attributes *StatAttributes) error {
|
||||
if !c.User.HasPerm(dataprovider.PermChtimes, pathForPerms) {
|
||||
return c.GetPermissionDeniedError()
|
||||
}
|
||||
|
||||
if c.ignoreSetStat() {
|
||||
return nil
|
||||
}
|
||||
if err := c.Fs.Chtimes(c.getRealFsPath(fsPath), attributes.Atime, attributes.Mtime); err != nil {
|
||||
c.Log(logger.LevelWarn, "failed to chtimes for path %#v, access time: %v, modification time: %v, err: %+v",
|
||||
fsPath, attributes.Atime, attributes.Mtime, err)
|
||||
@@ -494,6 +507,23 @@ func (c *BaseConnection) SetStat(fsPath, virtualPath string, attributes *StatAtt
|
||||
modificationTimeString := attributes.Mtime.Format(chtimesFormat)
|
||||
logger.CommandLog(chtimesLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1,
|
||||
accessTimeString, modificationTimeString, "", -1)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetStat set StatAttributes for the specified fsPath
|
||||
func (c *BaseConnection) SetStat(fsPath, virtualPath string, attributes *StatAttributes) error {
|
||||
pathForPerms := c.getPathForSetStatPerms(fsPath, virtualPath)
|
||||
|
||||
if attributes.Flags&StatAttrPerms != 0 {
|
||||
return c.handleChmod(fsPath, pathForPerms, attributes)
|
||||
}
|
||||
|
||||
if attributes.Flags&StatAttrUIDGID != 0 {
|
||||
return c.handleChown(fsPath, pathForPerms, attributes)
|
||||
}
|
||||
|
||||
if attributes.Flags&StatAttrTimes != 0 {
|
||||
return c.handleChtimes(fsPath, pathForPerms, attributes)
|
||||
}
|
||||
|
||||
if attributes.Flags&StatAttrSize != 0 {
|
||||
@@ -950,6 +980,8 @@ func (c *BaseConnection) GetFsError(err error) error {
|
||||
return c.GetNotExistError()
|
||||
} else if c.Fs.IsPermission(err) {
|
||||
return c.GetPermissionDeniedError()
|
||||
} else if c.Fs.IsNotSupported(err) {
|
||||
return c.GetOpUnsupportedError()
|
||||
} else if err != nil {
|
||||
return c.GetGenericError(err)
|
||||
}
|
||||
|
||||
@@ -496,6 +496,29 @@ func TestSetStat(t *testing.T) {
|
||||
err = c.SetStat(user.GetHomeDir(), "/", &StatAttributes{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = c.SetStat(dir2, "/dir1/file", &StatAttributes{
|
||||
Mode: os.ModePerm,
|
||||
Flags: StatAttrPerms,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
err = c.SetStat(dir1, "/dir2/file", &StatAttributes{
|
||||
UID: os.Getuid(),
|
||||
GID: os.Getgid(),
|
||||
Flags: StatAttrUIDGID,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
err = c.SetStat(dir1, "/dir3/file", &StatAttributes{
|
||||
Atime: time.Now(),
|
||||
Mtime: time.Now(),
|
||||
Flags: StatAttrTimes,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
Config.SetstatMode = 2
|
||||
assert.False(t, c.ignoreSetStat())
|
||||
c1 := NewBaseConnection("", ProtocolSFTP, user, newMockOsFs(false, fs.ConnectionID(), user.GetHomeDir()))
|
||||
assert.True(t, c1.ignoreSetStat())
|
||||
|
||||
Config.SetstatMode = oldSetStatMode
|
||||
// chmod
|
||||
err = c.SetStat(dir1, "/dir1/file", &StatAttributes{
|
||||
@@ -1146,6 +1169,12 @@ func TestErrorsMapping(t *testing.T) {
|
||||
} else {
|
||||
assert.EqualError(t, err, ErrPermissionDenied.Error())
|
||||
}
|
||||
err = conn.GetFsError(vfs.ErrVfsUnsupported)
|
||||
if protocol == ProtocolSFTP {
|
||||
assert.EqualError(t, err, sftp.ErrSSHFxOpUnsupported.Error())
|
||||
} else {
|
||||
assert.EqualError(t, err, ErrOpUnsupported.Error())
|
||||
}
|
||||
err = conn.GetFsError(nil)
|
||||
assert.NoError(t, err)
|
||||
err = conn.GetOpUnsupportedError()
|
||||
|
||||
@@ -4,10 +4,14 @@ SFTPGo provides an official Docker image, it is available on both [Docker Hub](h
|
||||
|
||||
## Supported tags and respective Dockerfile links
|
||||
|
||||
- [v1.2.0, v1.2, v1, latest](https://github.com/drakkan/sftpgo/blob/v1.2.0/Dockerfile)
|
||||
- [v1.2.0-alpine, v1.2-alpine, v1-alpine, alpine](https://github.com/drakkan/sftpgo/blob/v1.2.0/Dockerfile.alpine)
|
||||
- [edge](../Dockerfile)
|
||||
- [edge-alpine](../Dockerfile.alpine)
|
||||
- [v1.2.1, v1.2, v1, latest](https://github.com/drakkan/sftpgo/blob/v1.2.1/Dockerfile.full)
|
||||
- [v1.2.1-alpine, v1.2-alpine, v1-alpine, alpine](https://github.com/drakkan/sftpgo/blob/v1.2.1/Dockerfile.full.alpine)
|
||||
- [v1.2.1-slim, v1.2-slim, v1-slim, slim](https://github.com/drakkan/sftpgo/blob/v1.2.1/Dockerfile)
|
||||
- [v1.2.1-alpine-slim, v1.2-alpine-slim, v1-alpine-slim, alpine-slim](https://github.com/drakkan/sftpgo/blob/v1.2.1/Dockerfile.alpine)
|
||||
- [edge](../Dockerfile.full)
|
||||
- [edge-alpine](../Dockerfile.full.alpine)
|
||||
- [edge-slim](../Dockerfile)
|
||||
- [edge-alpine-slim](../Dockerfile.alpine)
|
||||
|
||||
## How to use the SFTPGo image
|
||||
|
||||
@@ -27,10 +31,10 @@ If you prefer GitHub Container Registry to Docker Hub replace `drakkan/sftpgo:ta
|
||||
|
||||
### Container shell access and viewing SFTPGo logs
|
||||
|
||||
The docker exec command allows you to run commands inside a Docker container. The following command line will give you a bash shell inside your `sftpgo` container:
|
||||
The docker exec command allows you to run commands inside a Docker container. The following command line will give you a shell inside your `sftpgo` container:
|
||||
|
||||
```shell
|
||||
docker exec -it some-sftpgo bash
|
||||
docker exec -it some-sftpgo sh
|
||||
```
|
||||
|
||||
The logs are available through Docker's container log:
|
||||
@@ -98,6 +102,15 @@ docker run --name some-sftpgo \
|
||||
-d "drakkan/sftpgo:tag"
|
||||
```
|
||||
|
||||
Alternately build your own image using the official one as a base, here is a sample Dockerfile:
|
||||
|
||||
```shell
|
||||
FROM drakkan/sftpgo:tag
|
||||
USER root
|
||||
RUN chown -R 1100:1100 /etc/sftpgo && chown 1100:1100 /var/lib/sftpgo /srv/sftpgo
|
||||
USER 1100:1100
|
||||
```
|
||||
|
||||
## Image Variants
|
||||
|
||||
The `sftpgo` images comes in many flavors, each designed for a specific use case. The `edge` and `edge-alpine`tags are updated after each new commit.
|
||||
@@ -112,6 +125,10 @@ This image is based on the popular [Alpine Linux project](https://alpinelinux.or
|
||||
|
||||
This variant is highly recommended when final image size being as small as possible is desired. The main caveat to note is that it does use [musl libc](https://musl.libc.org/) instead of [glibc and friends](https://www.etalabs.net/compare_libcs.html), so certain software might run into issues depending on the depth of their libc requirements. However, most software doesn't have an issue with this, so this variant is usually a very safe choice. See [this Hacker News comment thread](https://news.ycombinator.com/item?id=10782897) for more discussion of the issues that might arise and some pro/con comparisons of using Alpine-based images.
|
||||
|
||||
### `sftpgo:<suite>-slim`
|
||||
|
||||
These tags provide a slimmer image that does not include the optional `git` and `rsync` dependencies.
|
||||
|
||||
## Helm Chart
|
||||
|
||||
An helm chart is [available](https://artifacthub.io/packages/helm/sagikazarmark/sftpgo). You can find the source code [here](https://github.com/sagikazarmark/helm-charts/tree/master/charts/sftpgo).
|
||||
|
||||
28
docker/scripts/entrypoint-alpine.sh
Executable file
28
docker/scripts/entrypoint-alpine.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SFTPGO_PUID=${SFTPGO_PUID:-1000}
|
||||
SFTPGO_PGID=${SFTPGO_PGID:-1000}
|
||||
|
||||
if [ "$1" = 'sftpgo' ]; then
|
||||
if [ "$(id -u)" = '0' ]; then
|
||||
for DIR in "/etc/sftpgo" "/var/lib/sftpgo" "/srv/sftpgo"
|
||||
do
|
||||
DIR_UID=$(stat -c %u ${DIR})
|
||||
DIR_GID=$(stat -c %g ${DIR})
|
||||
if [ ${DIR_UID} != ${SFTPGO_PUID} ] || [ ${DIR_GID} != ${SFTPGO_PGID} ]; then
|
||||
echo '{"level":"info","time":"'`date +%Y-%m-%dT%H:%M:%S.000`'","sender":"entrypoint","message":"change owner for \"'${DIR}'\" UID: '${SFTPGO_PUID}' GID: '${SFTPGO_PGID}'"}'
|
||||
if [ ${DIR} = "/etc/sftpgo" ]; then
|
||||
chown -R ${SFTPGO_PUID}:${SFTPGO_PGID} ${DIR}
|
||||
else
|
||||
chown ${SFTPGO_PUID}:${SFTPGO_PGID} ${DIR}
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo '{"level":"info","time":"'`date +%Y-%m-%dT%H:%M:%S.000`'","sender":"entrypoint","message":"run as UID: '${SFTPGO_PUID}' GID: '${SFTPGO_PGID}'"}'
|
||||
exec su-exec ${SFTPGO_PUID}:${SFTPGO_PGID} "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
32
docker/scripts/entrypoint.sh
Executable file
32
docker/scripts/entrypoint.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SFTPGO_PUID=${SFTPGO_PUID:-1000}
|
||||
SFTPGO_PGID=${SFTPGO_PGID:-1000}
|
||||
|
||||
if [ "$1" = 'sftpgo' ]; then
|
||||
if [ "$(id -u)" = '0' ]; then
|
||||
getent passwd ${SFTPGO_PUID} > /dev/null
|
||||
HAS_PUID=$?
|
||||
getent group ${SFTPGO_PGID} > /dev/null
|
||||
HAS_PGID=$?
|
||||
if [ ${HAS_PUID} -ne 0 ] || [ ${HAS_PGID} -ne 0 ]; then
|
||||
echo '{"level":"info","time":"'`date +%Y-%m-%dT%H:%M:%S.%3N`'","sender":"entrypoint","message":"prepare to run as UID: '${SFTPGO_PUID}' GID: '${SFTPGO_PGID}'"}'
|
||||
if [ ${HAS_PGID} -ne 0 ]; then
|
||||
echo '{"level":"info","time":"'`date +%Y-%m-%dT%H:%M:%S.%3N`'","sender":"entrypoint","message":"set GID to: '${SFTPGO_PGID}'"}'
|
||||
groupmod -g ${SFTPGO_PGID} sftpgo
|
||||
fi
|
||||
if [ ${HAS_PUID} -ne 0 ]; then
|
||||
echo '{"level":"info","time":"'`date +%Y-%m-%dT%H:%M:%S.%3N`'","sender":"entrypoint","message":"set UID to: '${SFTPGO_PUID}'"}'
|
||||
usermod -u ${SFTPGO_PUID} sftpgo
|
||||
fi
|
||||
chown -R ${SFTPGO_PUID}:${SFTPGO_PGID} /etc/sftpgo
|
||||
chown ${SFTPGO_PUID}:${SFTPGO_PGID} /var/lib/sftpgo /srv/sftpgo
|
||||
fi
|
||||
echo '{"level":"info","time":"'`date +%Y-%m-%dT%H:%M:%S.%3N`'","sender":"entrypoint","message":"run as UID: '${SFTPGO_PUID}' GID: '${SFTPGO_PGID}'"}'
|
||||
exec gosu ${SFTPGO_PUID}:${SFTPGO_PGID} "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
@@ -54,7 +54,7 @@ The configuration file contains the following sections:
|
||||
- `actions`, struct. It contains the command to execute and/or the HTTP URL to notify and the trigger conditions. See [Custom Actions](./custom-actions.md) for more details
|
||||
- `execute_on`, list of strings. Valid values are `download`, `upload`, `pre-delete`, `delete`, `rename`, `ssh_cmd`. Leave empty to disable actions.
|
||||
- `hook`, string. Absolute path to the command to execute or HTTP URL to notify.
|
||||
- `setstat_mode`, integer. 0 means "normal mode": requests for changing permissions, owner/group and access/modification times are executed. 1 means "ignore mode": requests for changing permissions, owner/group and access/modification times are silently ignored.
|
||||
- `setstat_mode`, integer. 0 means "normal mode": requests for changing permissions, owner/group and access/modification times are executed. 1 means "ignore mode": requests for changing permissions, owner/group and access/modification times are silently ignored. 2 means "ignore mode for cloud based filesystems": requests for changing permissions, owner/group and access/modification times are silently ignored for cloud filesystems and executed for local filesystem.
|
||||
- `proxy_protocol`, integer. Support for [HAProxy PROXY protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt). If you are running SFTPGo behind a proxy server such as HAProxy, AWS ELB or NGNIX, you can enable the proxy protocol. It provides a convenient way to safely transport connection information such as a client's address across multiple layers of NAT or TCP proxies to get the real client IP address instead of the proxy IP. Both protocol versions 1 and 2 are supported. If the proxy protocol is enabled in SFTPGo then you have to enable the protocol in your proxy configuration too. For example, for HAProxy, add `send-proxy` or `send-proxy-v2` to each server configuration line. The following modes are supported:
|
||||
- 0, disabled
|
||||
- 1, enabled. Proxy header will be used and requests without proxy header will be accepted
|
||||
|
||||
@@ -20,9 +20,8 @@ The configured bucket must exist.
|
||||
|
||||
Some SFTP commands don't work over S3:
|
||||
|
||||
- `symlink` and `chtimes` will fail
|
||||
- `chown` and `chmod` are silently ignored
|
||||
- `truncate` is not supported
|
||||
- `chtimes`, `chown` and `chmod` will fail. If you want to silently ignore these method set `setstat_mode` to `1` or `2` in your configuration file
|
||||
- `truncate`, `symlink`, `readlink` are not supported
|
||||
- opening a file for both reading and writing at the same time is not supported
|
||||
- upload resume is not supported
|
||||
- upload mode `atomic` is ignored since S3 uploads are already atomic
|
||||
|
||||
27
go.mod
27
go.mod
@@ -3,12 +3,12 @@ module github.com/drakkan/sftpgo
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.71.0 // indirect
|
||||
cloud.google.com/go v0.72.0 // indirect
|
||||
cloud.google.com/go/storage v1.12.0
|
||||
github.com/Azure/azure-storage-blob-go v0.11.0
|
||||
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962
|
||||
github.com/alexedwards/argon2id v0.0.0-20200802152012-2464efd3196b
|
||||
github.com/aws/aws-sdk-go v1.35.23
|
||||
github.com/aws/aws-sdk-go v1.35.28
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
|
||||
github.com/eikenb/pipeat v0.0.0-20200430215831-470df5986b6d
|
||||
github.com/fclairamb/ftpserverlib v0.9.1-0.20201105003045-1edd6bf7ae53
|
||||
@@ -18,7 +18,7 @@ require (
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/grandcat/zeroconf v1.0.0
|
||||
github.com/jlaffaye/ftp v0.0.0-20200720194710-13949d38913e
|
||||
github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126
|
||||
github.com/lib/pq v1.8.0
|
||||
github.com/magiconair/properties v1.8.4 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.4
|
||||
@@ -29,9 +29,11 @@ require (
|
||||
github.com/pires/go-proxyproto v0.3.1
|
||||
github.com/pkg/sftp v1.12.1-0.20201002132022-fcaa492add82
|
||||
github.com/prometheus/client_golang v1.8.0
|
||||
github.com/prometheus/common v0.15.0 // indirect
|
||||
github.com/rs/cors v1.7.1-0.20200626170627-8b4a00bd362b
|
||||
github.com/rs/xid v1.2.1
|
||||
github.com/rs/zerolog v1.20.0
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/spf13/afero v1.4.1
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/spf13/cobra v1.1.1
|
||||
@@ -41,22 +43,21 @@ require (
|
||||
github.com/studio-b12/gowebdav v0.0.0-20200303150724-9380631c29a1
|
||||
go.etcd.io/bbolt v1.3.5
|
||||
go.uber.org/automaxprocs v1.3.0
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102
|
||||
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf
|
||||
golang.org/x/text v0.3.4 // indirect
|
||||
golang.org/x/tools v0.0.0-20201105220310-78b158585360 // indirect
|
||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 // indirect
|
||||
golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba
|
||||
golang.org/x/tools v0.0.0-20201113202037-1643af1435f3 // indirect
|
||||
google.golang.org/api v0.35.0
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20201106154455-f9bfe239b0ba // indirect
|
||||
google.golang.org/grpc v1.33.2 // indirect
|
||||
google.golang.org/genproto v0.0.0-20201113130914-ce600e9a6f9e // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
)
|
||||
|
||||
replace (
|
||||
github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20200730125632-b21eac28818c
|
||||
github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9
|
||||
github.com/pkg/sftp => github.com/drakkan/sftp v0.0.0-20201105171632-4ab2ef794ae3
|
||||
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20201017144935-4e8324213ac3
|
||||
golang.org/x/net => github.com/drakkan/net v0.0.0-20201104142514-34ad2afe5beb
|
||||
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20201114074711-d051624c4fd2
|
||||
golang.org/x/net => github.com/drakkan/net v0.0.0-20201114074615-8a2467084c77
|
||||
)
|
||||
|
||||
46
go.sum
46
go.sum
@@ -14,8 +14,8 @@ cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZ
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.66.0/go.mod h1:dgqGAjKCDxyhGTtC9dAREQGUJpkceNm1yt590Qno0Ko=
|
||||
cloud.google.com/go v0.71.0 h1:2ha722Z08cmRa0orJrzBaszYQcLbLFcsZHsGSj/kIF4=
|
||||
cloud.google.com/go v0.71.0/go.mod h1:qZfY4Y7AEIQwG/fQYD3xrxLNkQZ0Xzf3HGeqCkA6LVM=
|
||||
cloud.google.com/go v0.72.0 h1:eWRCuwubtDrCJG0oSUMgnsbD4CmPFQF2ei4OFbXvwww=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
@@ -71,8 +71,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
||||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.35.23 h1:SCP0d0XvyJTDmfnHEQPvBaYi3kea1VNUo7uQmkVgFts=
|
||||
github.com/aws/aws-sdk-go v1.35.23/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
|
||||
github.com/aws/aws-sdk-go v1.35.28 h1:S2LuRnfC8X05zgZLC8gy/Sb82TGv2Cpytzbzz7tkeHc=
|
||||
github.com/aws/aws-sdk-go v1.35.28/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
@@ -115,12 +115,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/drakkan/crypto v0.0.0-20201017144935-4e8324213ac3 h1:zMCXHTGF8QJ7GWQ2PL0P+nCB2AzV+v0dBsnoyQ4jVkY=
|
||||
github.com/drakkan/crypto v0.0.0-20201017144935-4e8324213ac3/go.mod h1:v3bhWOXGYda7H5d2s5t9XA6th3fxW3s0MQxU1R96G/w=
|
||||
github.com/drakkan/ftp v0.0.0-20200730125632-b21eac28818c h1:QSXIWohSNn0negBVSKEjKTpdpGEsW7weVW8QNzviLHY=
|
||||
github.com/drakkan/ftp v0.0.0-20200730125632-b21eac28818c/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
|
||||
github.com/drakkan/net v0.0.0-20201104142514-34ad2afe5beb h1:NgZ7GvppCYwS8iG+zcuQvzVCAvTQLtxVe7PSWxJtxhI=
|
||||
github.com/drakkan/net v0.0.0-20201104142514-34ad2afe5beb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
github.com/drakkan/crypto v0.0.0-20201114074711-d051624c4fd2 h1:1X+tt8X6lyGWn17TJaKOybGkRuGm1Rd0ErPhIY1Zy4A=
|
||||
github.com/drakkan/crypto v0.0.0-20201114074711-d051624c4fd2/go.mod h1:v3bhWOXGYda7H5d2s5t9XA6th3fxW3s0MQxU1R96G/w=
|
||||
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 h1:LPH1dEblAOO/LoG7yHPMtBLXhQmjaga91/DDjWk9jWA=
|
||||
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
|
||||
github.com/drakkan/net v0.0.0-20201114074615-8a2467084c77 h1:keiJPG0lodjq5Ep9XuDKGRQRC52pp/8NB8/1xbqmw+Y=
|
||||
github.com/drakkan/net v0.0.0-20201114074615-8a2467084c77/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
github.com/drakkan/sftp v0.0.0-20201105171632-4ab2ef794ae3 h1:9rug3vpr/986h/KeITYQQx78DErOAkOes+ktVRyTPQQ=
|
||||
github.com/drakkan/sftp v0.0.0-20201105171632-4ab2ef794ae3/go.mod h1:fUqqXB5vEgVCZ131L+9say31RAri6aF6KDViawhxKK8=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
@@ -412,8 +412,9 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4=
|
||||
github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM=
|
||||
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
@@ -432,13 +433,13 @@ github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=
|
||||
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4/go.mod h1:MnkX001NG75g3p8bhFycnyIjeQoOjGL6CEIsdE/nKSY=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
@@ -552,8 +553,9 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 h1:Mj83v+wSRNEar42a/MQgxk9X42TdEmrOl9i+y8WbxLo=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -608,8 +610,8 @@ golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf h1:kt3wY1Lu5MJAnKTfoMR52Cu4gwvna4VTzNOiT8tY73s=
|
||||
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba h1:xmhUJGQGbxlod18iJGqVEp9cHIPLl7QiX2aA3to708s=
|
||||
golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -674,8 +676,8 @@ golang.org/x/tools v0.0.0-20200828161849-5deb26317202/go.mod h1:njjCfa9FT2d7l9Bc
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20200915173823-2db8f0ff891c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201030143252-cf7a54d06671/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201105220310-78b158585360/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201113202037-1643af1435f3/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -699,7 +701,6 @@ google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSr
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.31.0/go.mod h1:CL+9IBCa2WWU6gRuBWaKqGWLFFwbEUXkfeMkHLQWYWo=
|
||||
google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.34.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.35.0 h1:TBCmTTxUrRDA1iTctnK/fIeitxIZ+TQuaf0j29fmCGo=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
@@ -744,9 +745,9 @@ google.golang.org/genproto v0.0.0-20200831141814-d751682dd103/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200914193844-75d14daec038/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200921151605-7abf4a1a14d5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201106154455-f9bfe239b0ba h1:HocWKLuilwaaLY56cHV38rw84wJ1nscA0Rs7OnO8mm8=
|
||||
google.golang.org/genproto v0.0.0-20201106154455-f9bfe239b0ba/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201113130914-ce600e9a6f9e h1:jRAe+6EDD0LNrVzmjx7FxBivivOZTKnXMbH5lvmxLP8=
|
||||
google.golang.org/genproto v0.0.0-20201113130914-ce600e9a6f9e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
@@ -766,7 +767,6 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
NFPM_VERSION=1.9.0
|
||||
NFPM_VERSION=1.10.1
|
||||
NFPM_ARCH=${NFPM_ARCH:-amd64}
|
||||
if [ -z ${SFTPGO_VERSION} ]
|
||||
then
|
||||
@@ -18,6 +18,7 @@ cd dist
|
||||
BASE_DIR="../.."
|
||||
|
||||
cp ${BASE_DIR}/sftpgo.json .
|
||||
cp ${BASE_DIR}/examples/rest-api-cli/sftpgo_api_cli .
|
||||
sed -i "s|sftpgo.db|/var/lib/sftpgo/sftpgo.db|" sftpgo.json
|
||||
sed -i "s|\"users_base_dir\": \"\",|\"users_base_dir\": \"/srv/sftpgo/data\",|" sftpgo.json
|
||||
sed -i "s|\"templates\"|\"/usr/share/sftpgo/templates\"|" sftpgo.json
|
||||
@@ -52,7 +53,7 @@ files:
|
||||
./sftpgo-completion.bash: "/usr/share/bash-completion/completions/sftpgo"
|
||||
./man1/*: "/usr/share/man/man1/"
|
||||
${BASE_DIR}/init/sftpgo.service: "/lib/systemd/system/sftpgo.service"
|
||||
${BASE_DIR}/examples/rest-api-cli/sftpgo_api_cli: "/usr/bin/sftpgo_api_cli"
|
||||
./sftpgo_api_cli: "/usr/bin/sftpgo_api_cli"
|
||||
${BASE_DIR}/templates/*: "/usr/share/sftpgo/templates/"
|
||||
${BASE_DIR}/static/**/*: "/usr/share/sftpgo/static/"
|
||||
|
||||
@@ -67,9 +68,10 @@ overrides:
|
||||
deb:
|
||||
recommends:
|
||||
- bash-completion
|
||||
- mime-support
|
||||
suggests:
|
||||
- python3-requests
|
||||
- python3-pygments
|
||||
- mime-support
|
||||
scripts:
|
||||
postinstall: ../scripts/deb/postinstall.sh
|
||||
preremove: ../scripts/deb/preremove.sh
|
||||
@@ -96,7 +98,8 @@ curl --retry 5 --retry-delay 2 --connect-timeout 10 -L -O \
|
||||
https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/nfpm_${NFPM_VERSION}_Linux_x86_64.tar.gz
|
||||
tar xvf nfpm_${NFPM_VERSION}_Linux_x86_64.tar.gz nfpm
|
||||
chmod 755 nfpm
|
||||
mkdir deb
|
||||
./nfpm -f nfpm.yaml pkg -p deb -t deb
|
||||
mkdir rpm
|
||||
./nfpm -f nfpm.yaml pkg -p rpm -t rpm
|
||||
sed -i "s|env python|env python3|" sftpgo_api_cli
|
||||
mkdir deb
|
||||
./nfpm -f nfpm.yaml pkg -p deb -t deb
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
sftpgo (1.2.0-1ppa1) bionic; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Nicola Murino <nicola.murino@gmail.com> Sun, 08 Nov 2020 06:59:19 +0100
|
||||
|
||||
sftpgo (1.1.1-1ppa2) bionic; urgency=medium
|
||||
|
||||
* Fix sftpgo data dir.
|
||||
|
||||
@@ -10,7 +10,8 @@ Vcs-Git: https://github.com/drakkan/sftpgo.git
|
||||
Package: sftpgo
|
||||
Architecture: amd64
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Recommends: bash-completion, python3-requests, python3-pygments, mime-support
|
||||
Recommends: bash-completion, mime-support
|
||||
Suggests: python3-requests, python3-pygments
|
||||
Description: Fully featured and highly configurable SFTP server
|
||||
SFTPGo has optional FTP/S and WebDAV support.
|
||||
It can serve local filesystem, S3 (Compatible) Object Storage,
|
||||
|
||||
@@ -2,7 +2,7 @@ Index: sftpgo/sftpgo.json
|
||||
===================================================================
|
||||
--- sftpgo.orig/sftpgo.json
|
||||
+++ sftpgo/sftpgo.json
|
||||
@@ -69,7 +69,7 @@
|
||||
@@ -74,7 +74,7 @@
|
||||
},
|
||||
"data_provider": {
|
||||
"driver": "sqlite",
|
||||
@@ -11,7 +11,7 @@ Index: sftpgo/sftpgo.json
|
||||
"host": "",
|
||||
"port": 5432,
|
||||
"username": "",
|
||||
@@ -80,14 +80,14 @@
|
||||
@@ -85,14 +85,14 @@
|
||||
"manage_users": 1,
|
||||
"track_quota": 2,
|
||||
"pool_size": 0,
|
||||
@@ -25,10 +25,10 @@ Index: sftpgo/sftpgo.json
|
||||
"external_auth_scope": 0,
|
||||
- "credentials_path": "credentials",
|
||||
+ "credentials_path": "/var/lib/sftpgo/credentials",
|
||||
"prefer_database_credentials": false,
|
||||
"pre_login_hook": "",
|
||||
"post_login_hook": "",
|
||||
"post_login_scope": 0,
|
||||
@@ -105,9 +105,9 @@
|
||||
@@ -111,9 +111,9 @@
|
||||
"httpd": {
|
||||
"bind_port": 8080,
|
||||
"bind_address": "127.0.0.1",
|
||||
@@ -41,10 +41,3 @@ Index: sftpgo/sftpgo.json
|
||||
"auth_user_file": "",
|
||||
"certificate_file": "",
|
||||
"certificate_key_file": ""
|
||||
@@ -117,4 +117,4 @@
|
||||
"ca_certificates": [],
|
||||
"skip_tls_verify": false
|
||||
}
|
||||
-}
|
||||
\ No newline at end of file
|
||||
+}
|
||||
|
||||
@@ -397,17 +397,6 @@ func TestSFTPCmdTargetPath(t *testing.T) {
|
||||
assert.True(t, os.IsNotExist(err))
|
||||
}
|
||||
|
||||
func TestSetstatModeIgnore(t *testing.T) {
|
||||
originalMode := common.Config.SetstatMode
|
||||
common.Config.SetstatMode = 1
|
||||
connection := Connection{}
|
||||
request := sftp.NewRequest("Setstat", "invalid")
|
||||
request.Flags = 0
|
||||
err := connection.handleSFTPSetstat("invalid", request)
|
||||
assert.NoError(t, err)
|
||||
common.Config.SetstatMode = originalMode
|
||||
}
|
||||
|
||||
func TestSFTPGetUsedQuota(t *testing.T) {
|
||||
u := dataprovider.User{}
|
||||
u.HomeDir = "home_rel_path"
|
||||
@@ -1680,6 +1669,13 @@ func TestTransferFailingReader(t *testing.T) {
|
||||
err = tr.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
tr = newTransfer(baseTransfer, nil, nil, errRead)
|
||||
_, err = tr.ReadAt(buf, 0)
|
||||
assert.EqualError(t, err, errRead.Error())
|
||||
|
||||
err = tr.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = os.Remove(fsPath)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, connection.GetTransfers(), 0)
|
||||
|
||||
@@ -32,6 +32,9 @@ func (r *failingReader) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
}
|
||||
|
||||
func (r *failingReader) Close() error {
|
||||
if r.innerReader == nil {
|
||||
return nil
|
||||
}
|
||||
return r.innerReader.Close()
|
||||
}
|
||||
|
||||
@@ -70,6 +73,12 @@ func newTransfer(baseTransfer *common.BaseTransfer, pipeWriter *vfs.PipeWriter,
|
||||
}
|
||||
}
|
||||
}
|
||||
if baseTransfer.File == nil && errForRead != nil && pipeReader == nil {
|
||||
reader = &failingReader{
|
||||
innerReader: nil,
|
||||
errRead: errForRead,
|
||||
}
|
||||
}
|
||||
return &transfer{
|
||||
BaseTransfer: baseTransfer,
|
||||
writerAt: writer,
|
||||
|
||||
@@ -2,7 +2,7 @@ package version
|
||||
|
||||
import "strings"
|
||||
|
||||
const version = "1.2.0"
|
||||
const version = "1.2.1"
|
||||
|
||||
var (
|
||||
commit = ""
|
||||
|
||||
@@ -361,37 +361,34 @@ func (fs *AzureBlobFs) Mkdir(name string) error {
|
||||
|
||||
// Symlink creates source as a symbolic link to target.
|
||||
func (*AzureBlobFs) Symlink(source, target string) error {
|
||||
return errors.New("403 symlinks are not supported")
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Readlink returns the destination of the named symbolic link
|
||||
func (*AzureBlobFs) Readlink(name string) (string, error) {
|
||||
return "", errors.New("403 readlink is not supported")
|
||||
return "", ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Chown changes the numeric uid and gid of the named file.
|
||||
// Silently ignored.
|
||||
func (*AzureBlobFs) Chown(name string, uid int, gid int) error {
|
||||
return nil
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Chmod changes the mode of the named file to mode.
|
||||
// Silently ignored.
|
||||
func (*AzureBlobFs) Chmod(name string, mode os.FileMode) error {
|
||||
return nil
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Chtimes changes the access and modification times of the named file.
|
||||
// Silently ignored.
|
||||
func (*AzureBlobFs) Chtimes(name string, atime, mtime time.Time) error {
|
||||
return errors.New("403 chtimes is not supported")
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Truncate changes the size of the named file.
|
||||
// Truncate by path is not supported, while truncating an opened
|
||||
// file is handled inside base transfer
|
||||
func (*AzureBlobFs) Truncate(name string, size int64) error {
|
||||
return errors.New("403 truncate is not supported")
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// ReadDir reads the directory named by dirname and returns
|
||||
@@ -519,6 +516,14 @@ func (*AzureBlobFs) IsPermission(err error) bool {
|
||||
return strings.Contains(err.Error(), "403")
|
||||
}
|
||||
|
||||
// IsNotSupported returns true if the error indicate an unsupported operation
|
||||
func (*AzureBlobFs) IsNotSupported(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
return err == ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// CheckRootPath creates the specified local root directory if it does not exists
|
||||
func (fs *AzureBlobFs) CheckRootPath(username string, uid int, gid int) bool {
|
||||
// we need a local directory for temporary files
|
||||
@@ -575,7 +580,7 @@ func (fs *AzureBlobFs) ScanRootDirContents() (int, int64, error) {
|
||||
// GetDirSize returns the number of files and the size for a folder
|
||||
// including any subfolders
|
||||
func (*AzureBlobFs) GetDirSize(dirname string) (int, int64, error) {
|
||||
return 0, 0, errUnsupported
|
||||
return 0, 0, ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// GetAtomicUploadPath returns the path to use for an atomic upload.
|
||||
|
||||
31
vfs/gcsfs.go
31
vfs/gcsfs.go
@@ -218,8 +218,12 @@ func (fs *GCSFs) Create(name string, flag int) (*os.File, *PipeWriter, func(), e
|
||||
}
|
||||
go func() {
|
||||
defer cancelFn()
|
||||
defer objectWriter.Close()
|
||||
|
||||
n, err := io.Copy(objectWriter, r)
|
||||
closeErr := objectWriter.Close()
|
||||
if err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
r.CloseWithError(err) //nolint:errcheck
|
||||
p.Done(err)
|
||||
fsLog(fs, logger.LevelDebug, "upload completed, path: %#v, readed bytes: %v, err: %v", name, n, err)
|
||||
@@ -314,37 +318,34 @@ func (fs *GCSFs) Mkdir(name string) error {
|
||||
|
||||
// Symlink creates source as a symbolic link to target.
|
||||
func (*GCSFs) Symlink(source, target string) error {
|
||||
return errors.New("403 symlinks are not supported")
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Readlink returns the destination of the named symbolic link
|
||||
func (*GCSFs) Readlink(name string) (string, error) {
|
||||
return "", errors.New("403 readlink is not supported")
|
||||
return "", ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Chown changes the numeric uid and gid of the named file.
|
||||
// Silently ignored.
|
||||
func (*GCSFs) Chown(name string, uid int, gid int) error {
|
||||
return nil
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Chmod changes the mode of the named file to mode.
|
||||
// Silently ignored.
|
||||
func (*GCSFs) Chmod(name string, mode os.FileMode) error {
|
||||
return nil
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Chtimes changes the access and modification times of the named file.
|
||||
// Silently ignored.
|
||||
func (*GCSFs) Chtimes(name string, atime, mtime time.Time) error {
|
||||
return errors.New("403 chtimes is not supported")
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Truncate changes the size of the named file.
|
||||
// Truncate by path is not supported, while truncating an opened
|
||||
// file is handled inside base transfer
|
||||
func (*GCSFs) Truncate(name string, size int64) error {
|
||||
return errors.New("403 truncate is not supported")
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// ReadDir reads the directory named by dirname and returns
|
||||
@@ -455,6 +456,14 @@ func (*GCSFs) IsPermission(err error) bool {
|
||||
return strings.Contains(err.Error(), "403")
|
||||
}
|
||||
|
||||
// IsNotSupported returns true if the error indicate an unsupported operation
|
||||
func (*GCSFs) IsNotSupported(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
return err == ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// CheckRootPath creates the specified local root directory if it does not exists
|
||||
func (fs *GCSFs) CheckRootPath(username string, uid int, gid int) bool {
|
||||
// we need a local directory for temporary files
|
||||
@@ -502,7 +511,7 @@ func (fs *GCSFs) ScanRootDirContents() (int, int64, error) {
|
||||
// GetDirSize returns the number of files and the size for a folder
|
||||
// including any subfolders
|
||||
func (*GCSFs) GetDirSize(dirname string) (int, int64, error) {
|
||||
return 0, 0, errUnsupported
|
||||
return 0, 0, ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// GetAtomicUploadPath returns the path to use for an atomic upload.
|
||||
|
||||
@@ -185,6 +185,14 @@ func (*OsFs) IsPermission(err error) bool {
|
||||
return os.IsPermission(err)
|
||||
}
|
||||
|
||||
// IsNotSupported returns true if the error indicate an unsupported operation
|
||||
func (*OsFs) IsNotSupported(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
return err == ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// CheckRootPath creates the root directory if it does not exists
|
||||
func (fs *OsFs) CheckRootPath(username string, uid int, gid int) bool {
|
||||
var err error
|
||||
|
||||
25
vfs/s3fs.go
25
vfs/s3fs.go
@@ -350,37 +350,34 @@ func (fs *S3Fs) Mkdir(name string) error {
|
||||
|
||||
// Symlink creates source as a symbolic link to target.
|
||||
func (*S3Fs) Symlink(source, target string) error {
|
||||
return errors.New("403 symlinks are not supported")
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Readlink returns the destination of the named symbolic link
|
||||
func (*S3Fs) Readlink(name string) (string, error) {
|
||||
return "", errors.New("403 readlink is not supported")
|
||||
return "", ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Chown changes the numeric uid and gid of the named file.
|
||||
// Silently ignored.
|
||||
func (*S3Fs) Chown(name string, uid int, gid int) error {
|
||||
return nil
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Chmod changes the mode of the named file to mode.
|
||||
// Silently ignored.
|
||||
func (*S3Fs) Chmod(name string, mode os.FileMode) error {
|
||||
return nil
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Chtimes changes the access and modification times of the named file.
|
||||
// Silently ignored.
|
||||
func (*S3Fs) Chtimes(name string, atime, mtime time.Time) error {
|
||||
return errors.New("403 chtimes is not supported")
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// Truncate changes the size of the named file.
|
||||
// Truncate by path is not supported, while truncating an opened
|
||||
// file is handled inside base transfer
|
||||
func (*S3Fs) Truncate(name string, size int64) error {
|
||||
return errors.New("403 truncate is not supported")
|
||||
return ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// ReadDir reads the directory named by dirname and returns
|
||||
@@ -485,6 +482,14 @@ func (*S3Fs) IsPermission(err error) bool {
|
||||
return strings.Contains(err.Error(), "403")
|
||||
}
|
||||
|
||||
// IsNotSupported returns true if the error indicate an unsupported operation
|
||||
func (*S3Fs) IsNotSupported(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
return err == ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// CheckRootPath creates the specified local root directory if it does not exists
|
||||
func (fs *S3Fs) CheckRootPath(username string, uid int, gid int) bool {
|
||||
// we need a local directory for temporary files
|
||||
@@ -520,7 +525,7 @@ func (fs *S3Fs) ScanRootDirContents() (int, int64, error) {
|
||||
// GetDirSize returns the number of files and the size for a folder
|
||||
// including any subfolders
|
||||
func (*S3Fs) GetDirSize(dirname string) (int, int64, error) {
|
||||
return 0, 0, errUnsupported
|
||||
return 0, 0, ErrVfsUnsupported
|
||||
}
|
||||
|
||||
// GetAtomicUploadPath returns the path to use for an atomic upload.
|
||||
|
||||
@@ -46,6 +46,7 @@ type Fs interface {
|
||||
ResolvePath(sftpPath string) (string, error)
|
||||
IsNotExist(err error) bool
|
||||
IsPermission(err error) bool
|
||||
IsNotSupported(err error) bool
|
||||
ScanRootDirContents() (int, int64, error)
|
||||
GetDirSize(dirname string) (int, int64, error)
|
||||
GetAtomicUploadPath(name string) string
|
||||
@@ -56,7 +57,8 @@ type Fs interface {
|
||||
GetMimeType(name string) (string, error)
|
||||
}
|
||||
|
||||
var errUnsupported = errors.New("Not supported")
|
||||
// ErrVfsUnsupported defines the error for an unsupported VFS operation
|
||||
var ErrVfsUnsupported = errors.New("Not supported")
|
||||
|
||||
// QuotaCheckResult defines the result for a quota check
|
||||
type QuotaCheckResult struct {
|
||||
|
||||
Reference in New Issue
Block a user