Compare commits

...

11 Commits

Author SHA1 Message Date
Nicola Murino
4445834fd3 set version to 1.2.1 2020-11-14 09:28:53 +01:00
Nicola Murino
19a619ff65 Linux pkgs: use python3 for API CLI inside generated deb 2020-11-14 09:10:45 +01:00
Nicola Murino
66a538dc9c CI: improve docker build action 2020-11-13 21:55:53 +01:00
Nicola Murino
1a6863f4b1 GCS uploads: check Close() error
some code simplification too
2020-11-13 18:40:18 +01:00
Nicola Murino
fbd9919afa docker: add slim image 2020-11-12 22:40:53 +01:00
Nicola Murino
eec8bc73f4 docker: remove entrypoint
remove the VOLUME instruction from the Dockerfile so you can change
user using your own image like this:

FROM drakkan/sftpgo:tag
USER root
RUN chown -R 1100:1100 /etc/sftpgo && chown 1100:1100 /var/lib/sftpgo /srv/sftpgo
USER 1100:1100
2020-11-12 11:53:05 +01:00
Nicola Murino
5720d40fee add setstat_mode 2
in this mode chmod/chtimes/chown can be silently ignored only for cloud
based file systems

Fixes #223
2020-11-12 10:39:46 +01:00
Nicola Murino
38e0cba675 docker: add an entrypoint
running as an arbitrary user is now possible setting the following
env vars too:

SFTPGO_PUID
SFTPGO_PGID

Fixes #217
2020-11-10 23:11:57 +01:00
Nicola Murino
4c5a0d663e sftpd: return the error Operation Unsupported for unexpected reads
a cloud based file cannot be opened for read and write at the same
time. Return a proper error if a client try to do this.

It can happen only for SFTP
2020-11-09 21:01:56 +01:00
Nicola Murino
093df15fac CI: add ppc64le support 2020-11-09 18:39:36 +01:00
Nicola Murino
957430e675 back to development 2020-11-08 12:56:37 +01:00
30 changed files with 520 additions and 193 deletions

View File

@@ -86,7 +86,7 @@ jobs:
with: with:
dest: cross dest: cross
prefix: sftpgo prefix: sftpgo
targets: linux/arm64 targets: linux/arm64,linux/ppc64le
v: true v: true
x: false x: false
race: false race: false
@@ -108,7 +108,12 @@ jobs:
./sftpgo gen completion zsh > output/zsh_completion/_sftpgo ./sftpgo gen completion zsh > output/zsh_completion/_sftpgo
./sftpgo gen man -d output/man/man1 ./sftpgo gen man -d output/man/man1
gzip 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 - name: Prepare build artifact for Windows
if: startsWith(matrix.os, 'windows-') if: startsWith(matrix.os, 'windows-')
@@ -132,6 +137,7 @@ jobs:
if: ${{ matrix.upload-coverage && startsWith(matrix.os, 'ubuntu-') }} if: ${{ matrix.upload-coverage && startsWith(matrix.os, 'ubuntu-') }}
run: | run: |
cp -r pkgs pkgs_arm64 cp -r pkgs pkgs_arm64
cp -r pkgs pkgs_ppc64le
cd pkgs cd pkgs
./build.sh ./build.sh
cd .. cd ..
@@ -140,6 +146,12 @@ jobs:
cp cross/sftpgo${BIN_SUFFIX} . cp cross/sftpgo${BIN_SUFFIX} .
cd pkgs_arm64 cd pkgs_arm64
./build.sh ./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) PKG_VERSION=$(cat dist/version)
echo "::set-output name=pkg-version::${PKG_VERSION}" echo "::set-output name=pkg-version::${PKG_VERSION}"
@@ -162,14 +174,28 @@ jobs:
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: sftpgo-${{ steps.build_linux_pkgs.outputs.pkg-version }}-arm64-deb 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 - name: Upload RPM Package arm64
if: ${{ matrix.upload-coverage && startsWith(matrix.os, 'ubuntu-') }} if: ${{ matrix.upload-coverage && startsWith(matrix.os, 'ubuntu-') }}
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: sftpgo-${{ steps.build_linux_pkgs.outputs.pkg-version }}-arm64-rpm 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: test-postgresql-mysql:
name: Test with PostgreSQL/MySQL name: Test with PostgreSQL/MySQL

View File

@@ -21,9 +21,6 @@ jobs:
docker_pkg: docker_pkg:
- debian - debian
- alpine - alpine
docker_image:
- drakkan/sftpgo
- ghcr.io/drakkan/sftpgo
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -40,7 +37,8 @@ jobs:
id: info id: info
run: | run: |
VERSION=noop VERSION=noop
DOCKERFILE=Dockerfile DOCKERFILE_SLIM=Dockerfile
DOCKERFILE=Dockerfile.full
MINOR="" MINOR=""
MAJOR="" MAJOR=""
if [ "${{ github.event_name }}" = "schedule" ]; then if [ "${{ github.event_name }}" = "schedule" ]; then
@@ -59,45 +57,72 @@ jobs:
MINOR=${VERSION%.*} MINOR=${VERSION%.*}
MAJOR=${MINOR%.*} MAJOR=${MINOR%.*}
fi fi
VERSION_SLIM="${VERSION}-slim"
if [[ $DOCKER_PKG == alpine ]]; then if [[ $DOCKER_PKG == alpine ]]; then
VERSION="${VERSION}-alpine" VERSION="${VERSION}-alpine"
DOCKERFILE=Dockerfile.alpine VERSION_SLIM="${VERSION}-slim"
DOCKERFILE_SLIM=Dockerfile.alpine
DOCKERFILE=Dockerfile.full.alpine
fi fi
TAGS="${DOCKER_IMAGE}:${VERSION}"
if [[ $GITHUB_REF == refs/tags/* ]]; then DOCKER_IMAGES=("drakkan/sftpgo" "ghcr.io/drakkan/sftpgo")
if [[ $DOCKER_PKG == debian ]]; then TAGS="${DOCKER_IMAGES[0]}:${VERSION}"
if [[ -n $MAJOR && -n $MINOR ]]; then TAGS_SLIM="${DOCKER_IMAGES[0]}:${VERSION_SLIM}"
TAGS="$TAGS,${DOCKER_IMAGE}:${MINOR},${DOCKER_IMAGE}:${MAJOR}" BASE_IMAGE="${TAGS_SLIM}"
fi
TAGS="$TAGS,${DOCKER_IMAGE}:latest" for DOCKER_IMAGE in ${DOCKER_IMAGES[@]}; do
else if [[ ${DOCKER_IMAGE} != ${DOCKER_IMAGES[0]} ]]; then
if [[ -n $MAJOR && -n $MINOR ]]; then TAGS="${TAGS},${DOCKER_IMAGE}:${VERSION}"
TAGS="$TAGS,${DOCKER_IMAGE}:${MINOR}-alpine,${DOCKER_IMAGE}:${MAJOR}-alpine" TAGS_SLIM="${TAGS_SLIM},${DOCKER_IMAGE}:${VERSION_SLIM}"
fi
TAGS="$TAGS,${DOCKER_IMAGE}:alpine"
fi fi
fi 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_SLIM="${TAGS_SLIM},${DOCKER_IMAGE}:${MINOR}-slim,${DOCKER_IMAGE}:${MAJOR}-slim"
fi
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_SLIM="${TAGS_SLIM},${DOCKER_IMAGE}:${MINOR}-alpine-slim,${DOCKER_IMAGE}:${MAJOR}-alpine-slim"
fi
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::${DOCKERFILE}
echo ::set-output name=dockerfile-slim::${DOCKERFILE_SLIM}
echo ::set-output name=version::${VERSION} 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::${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=created::$(date -u +'%Y-%m-%dT%H:%M:%SZ')
echo ::set-output name=sha::${GITHUB_SHA::8} echo ::set-output name=sha::${GITHUB_SHA::8}
env: env:
DOCKER_PKG: ${{ matrix.docker_pkg }} DOCKER_PKG: ${{ matrix.docker_pkg }}
DOCKER_IMAGE: ${{ matrix.docker_image }}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx - name: Set up builder slim
uses: docker/setup-buildx-action@v1 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 - name: Login to Docker Hub
uses: docker/login-action@v1 uses: docker/login-action@v1
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} 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 - name: Login to GitHub Container Registry
uses: docker/login-action@v1 uses: docker/login-action@v1
@@ -105,15 +130,16 @@ jobs:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.CR_PAT }} 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 uses: docker/build-push-action@v2
with: 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 platforms: linux/amd64,linux/arm64,linux/ppc64le
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.info.outputs.tags }} tags: ${{ steps.info.outputs.tags-slim }}
build-args: | build-args: |
COMMIT_SHA=${{ steps.info.outputs.sha }} COMMIT_SHA=${{ steps.info.outputs.sha }}
labels: | 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.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.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.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.version=${{ steps.info.outputs.version }}
org.opencontainers.image.created=${{ steps.info.outputs.created }} org.opencontainers.image.created=${{ steps.info.outputs.created }}
org.opencontainers.image.revision=${{ github.sha }} org.opencontainers.image.revision=${{ github.sha }}

View File

@@ -5,7 +5,7 @@ on:
tags: 'v*' tags: 'v*'
env: env:
GO_VERSION: 1.15.4 GO_VERSION: 1.15.5
jobs: jobs:
create-release: create-release:
@@ -160,7 +160,7 @@ jobs:
with: with:
dest: cross dest: cross
prefix: sftpgo prefix: sftpgo
targets: linux/arm64 targets: linux/arm64,linux/ppc64le
v: true v: true
x: false x: false
race: false race: false
@@ -191,7 +191,12 @@ jobs:
./sftpgo gen man -d output/man/man1 ./sftpgo gen man -d output/man/man1
gzip output/man/man1/* gzip output/man/man1/*
cp examples/rest-api-cli/sftpgo_api_cli output/examples/rest-api-cli/ cp examples/rest-api-cli/sftpgo_api_cli output/examples/rest-api-cli/
cp -r output output_arm64 if [ $OS == 'linux' ]
then
cp -r output output_arm64
cp -r output output_ppc64le
cp -r output output_all
fi
cd output cd output
tar cJvf sftpgo_${SFTPGO_VERSION}_${OS}_x86_64.tar.xz * tar cJvf sftpgo_${SFTPGO_VERSION}_${OS}_x86_64.tar.xz *
cd .. cd ..
@@ -201,6 +206,16 @@ jobs:
cd output_arm64 cd output_arm64
tar cJvf sftpgo_${SFTPGO_VERSION}_${OS}_arm64.tar.xz * tar cJvf sftpgo_${SFTPGO_VERSION}_${OS}_arm64.tar.xz *
cd .. 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 fi
env: env:
SFTPGO_VERSION: ${{ steps.get_version.outputs.VERSION }} SFTPGO_VERSION: ${{ steps.get_version.outputs.VERSION }}
@@ -211,6 +226,7 @@ jobs:
if: ${{ matrix.os == 'ubuntu-latest' }} if: ${{ matrix.os == 'ubuntu-latest' }}
run: | run: |
cp -r pkgs pkgs_arm64 cp -r pkgs pkgs_arm64
cp -r pkgs pkgs_ppc64le
cd pkgs cd pkgs
./build.sh ./build.sh
cd .. cd ..
@@ -219,6 +235,13 @@ jobs:
cp cross/sftpgo${BIN_SUFFIX} . cp cross/sftpgo${BIN_SUFFIX} .
cd pkgs_arm64 cd pkgs_arm64
./build.sh ./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} PKG_VERSION=${SFTPGO_VERSION:1}
echo "::set-output name=pkg-version::${PKG_VERSION}" echo "::set-output name=pkg-version::${PKG_VERSION}"
env: env:
@@ -294,6 +317,28 @@ jobs:
asset_name: sftpgo_${{ steps.get_version.outputs.VERSION }}_${{ steps.get_os_name.outputs.OS }}_arm64.tar.xz asset_name: sftpgo_${{ steps.get_version.outputs.VERSION }}_${{ steps.get_os_name.outputs.OS }}_arm64.tar.xz
asset_content_type: application/x-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 - name: Upload Windows Release
if: startsWith(matrix.os, 'windows-') if: startsWith(matrix.os, 'windows-')
uses: actions/upload-release-asset@v1 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_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_name: sftpgo-${{ steps.build_linux_pkgs.outputs.pkg-version }}-1.aarch64.rpm
asset_content_type: application/x-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

View File

@@ -25,9 +25,7 @@ RUN set -xe && \
FROM debian:buster-slim FROM debian:buster-slim
RUN apt-get update && apt-get install --no-install-recommends -y ca-certificates mime-support && apt-get clean RUN apt-get update && apt-get install --no-install-recommends -y ca-certificates mime-support && rm -rf /var/lib/apt/lists/*
SHELL ["/bin/bash", "-c"]
RUN mkdir -p /etc/sftpgo /var/lib/sftpgo /usr/share/sftpgo /srv/sftpgo 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 \ --home-dir /var/lib/sftpgo --shell /usr/sbin/nologin \
--comment "SFTPGo user" --uid 1000 sftpgo --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/sftpgo.json /etc/sftpgo/sftpgo.json
COPY --from=builder /workspace/templates /usr/share/sftpgo/templates COPY --from=builder /workspace/templates /usr/share/sftpgo/templates
COPY --from=builder /workspace/static /usr/share/sftpgo/static 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|\"backups\"|\"/srv/sftpgo/backups\"|" /etc/sftpgo/sftpgo.json && \
sed -i "s|\"bind_address\": \"127.0.0.1\",|\"bind_address\": \"\",|" /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 RUN chown -R sftpgo:sftpgo /etc/sftpgo && chown sftpgo:sftpgo /var/lib/sftpgo /srv/sftpgo
WORKDIR /var/lib/sftpgo WORKDIR /var/lib/sftpgo
USER 1000:1000 USER 1000:1000
VOLUME [ "/var/lib/sftpgo", "/srv/sftpgo" ] CMD ["sftpgo", "serve"]
CMD sftpgo serve

View File

@@ -28,9 +28,7 @@ RUN set -xe && \
FROM alpine:3.12 FROM alpine:3.12
RUN apk add --update --no-cache ca-certificates tzdata bash mailcap RUN apk add --update --no-cache ca-certificates tzdata mailcap
SHELL ["/bin/bash", "-c"]
# set up nsswitch.conf for Go's "netgo" implementation # set up nsswitch.conf for Go's "netgo" implementation
# https://github.com/gliderlabs/docker-alpine/issues/367#issuecomment-424546457 # 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 mkdir -p /etc/sftpgo /var/lib/sftpgo /usr/share/sftpgo /srv/sftpgo
RUN addgroup -g 1000 -S sftpgo && \ RUN addgroup -g 1000 -S sftpgo && \
adduser -u 1000 -h /var/lib/sftpgo -s /sbin/nologin -G sftpgo -S -D -H sftpgo adduser -u 1000 -h /var/lib/sftpgo -s /sbin/nologin -G sftpgo -S -D -H -g "SFTPGo user" sftpgo
# Install some optional packages used by SFTPGo features
RUN apk add --update --no-cache rsync git
COPY --from=builder /workspace/sftpgo.json /etc/sftpgo/sftpgo.json COPY --from=builder /workspace/sftpgo.json /etc/sftpgo/sftpgo.json
COPY --from=builder /workspace/templates /usr/share/sftpgo/templates 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 WORKDIR /var/lib/sftpgo
USER 1000:1000 USER 1000:1000
VOLUME [ "/var/lib/sftpgo", "/srv/sftpgo" ] CMD ["sftpgo", "serve"]
CMD sftpgo serve

10
Dockerfile.full Normal file
View 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
View 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

View File

@@ -4,6 +4,7 @@
[![Code Coverage](https://codecov.io/gh/drakkan/sftpgo/branch/master/graph/badge.svg)](https://codecov.io/gh/drakkan/sftpgo/branch/master) [![Code Coverage](https://codecov.io/gh/drakkan/sftpgo/branch/master/graph/badge.svg)](https://codecov.io/gh/drakkan/sftpgo/branch/master)
[![Go Report Card](https://goreportcard.com/badge/github.com/drakkan/sftpgo)](https://goreportcard.com/report/github.com/drakkan/sftpgo) [![Go Report Card](https://goreportcard.com/badge/github.com/drakkan/sftpgo)](https://goreportcard.com/report/github.com/drakkan/sftpgo)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Docker Pulls](https://img.shields.io/docker/pulls/drakkan/sftpgo)](https://hub.docker.com/r/drakkan/sftpgo)
[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go) [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)
Fully featured and highly configurable SFTP server with optional FTP/S and WebDAV support, written in Go. Fully featured and highly configurable SFTP server with optional FTP/S and WebDAV support, written in Go.

View File

@@ -223,6 +223,8 @@ type Configuration struct {
Actions ProtocolActions `json:"actions" mapstructure:"actions"` Actions ProtocolActions `json:"actions" mapstructure:"actions"`
// SetstatMode 0 means "normal mode": requests for changing permissions and owner/group are executed. // 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. // 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"` SetstatMode int `json:"setstat_mode" mapstructure:"setstat_mode"`
// Support for HAProxy PROXY protocol. // Support for HAProxy PROXY protocol.
// If you are running SFTPGo behind a proxy server such as HAProxy, AWS ELB or NGNIX, you can enable // If you are running SFTPGo behind a proxy server such as HAProxy, AWS ELB or NGNIX, you can enable

View File

@@ -448,52 +448,82 @@ func (c *BaseConnection) DoStat(fsPath string, mode int) (os.FileInfo, error) {
return c.Fs.Stat(c.getRealFsPath(fsPath)) return c.Fs.Stat(c.getRealFsPath(fsPath))
} }
// SetStat set StatAttributes for the specified fsPath func (c *BaseConnection) ignoreSetStat() bool {
func (c *BaseConnection) SetStat(fsPath, virtualPath string, attributes *StatAttributes) error {
if Config.SetstatMode == 1 { if Config.SetstatMode == 1 {
return true
}
if Config.SetstatMode == 2 && !vfs.IsLocalOsFs(c.Fs) {
return true
}
return false
}
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 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
}
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)
return c.GetFsError(err)
}
logger.CommandLog(chownLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, attributes.UID, attributes.GID,
"", "", "", -1)
return nil
}
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)
return c.GetFsError(err)
}
accessTimeString := attributes.Atime.Format(chtimesFormat)
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) pathForPerms := c.getPathForSetStatPerms(fsPath, virtualPath)
if attributes.Flags&StatAttrPerms != 0 { if attributes.Flags&StatAttrPerms != 0 {
if !c.User.HasPerm(dataprovider.PermChmod, pathForPerms) { return c.handleChmod(fsPath, pathForPerms, attributes)
return c.GetPermissionDeniedError()
}
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)
} }
if attributes.Flags&StatAttrUIDGID != 0 { if attributes.Flags&StatAttrUIDGID != 0 {
if !c.User.HasPerm(dataprovider.PermChown, pathForPerms) { return c.handleChown(fsPath, pathForPerms, attributes)
return c.GetPermissionDeniedError()
}
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)
return c.GetFsError(err)
}
logger.CommandLog(chownLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, attributes.UID, attributes.GID,
"", "", "", -1)
} }
if attributes.Flags&StatAttrTimes != 0 { if attributes.Flags&StatAttrTimes != 0 {
if !c.User.HasPerm(dataprovider.PermChtimes, pathForPerms) { return c.handleChtimes(fsPath, pathForPerms, attributes)
return c.GetPermissionDeniedError()
}
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)
return c.GetFsError(err)
}
accessTimeString := attributes.Atime.Format(chtimesFormat)
modificationTimeString := attributes.Mtime.Format(chtimesFormat)
logger.CommandLog(chtimesLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1,
accessTimeString, modificationTimeString, "", -1)
} }
if attributes.Flags&StatAttrSize != 0 { if attributes.Flags&StatAttrSize != 0 {
@@ -950,6 +980,8 @@ func (c *BaseConnection) GetFsError(err error) error {
return c.GetNotExistError() return c.GetNotExistError()
} else if c.Fs.IsPermission(err) { } else if c.Fs.IsPermission(err) {
return c.GetPermissionDeniedError() return c.GetPermissionDeniedError()
} else if c.Fs.IsNotSupported(err) {
return c.GetOpUnsupportedError()
} else if err != nil { } else if err != nil {
return c.GetGenericError(err) return c.GetGenericError(err)
} }

View File

@@ -496,6 +496,29 @@ func TestSetStat(t *testing.T) {
err = c.SetStat(user.GetHomeDir(), "/", &StatAttributes{}) err = c.SetStat(user.GetHomeDir(), "/", &StatAttributes{})
assert.NoError(t, err) 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 Config.SetstatMode = oldSetStatMode
// chmod // chmod
err = c.SetStat(dir1, "/dir1/file", &StatAttributes{ err = c.SetStat(dir1, "/dir1/file", &StatAttributes{
@@ -1146,6 +1169,12 @@ func TestErrorsMapping(t *testing.T) {
} else { } else {
assert.EqualError(t, err, ErrPermissionDenied.Error()) 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) err = conn.GetFsError(nil)
assert.NoError(t, err) assert.NoError(t, err)
err = conn.GetOpUnsupportedError() err = conn.GetOpUnsupportedError()

View File

@@ -4,10 +4,14 @@ SFTPGo provides an official Docker image, it is available on both [Docker Hub](h
## Supported tags and respective Dockerfile links ## 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.1, v1.2, v1, latest](https://github.com/drakkan/sftpgo/blob/v1.2.1/Dockerfile.full)
- [v1.2.0-alpine, v1.2-alpine, v1-alpine, alpine](https://github.com/drakkan/sftpgo/blob/v1.2.0/Dockerfile.alpine) - [v1.2.1-alpine, v1.2-alpine, v1-alpine, alpine](https://github.com/drakkan/sftpgo/blob/v1.2.1/Dockerfile.full.alpine)
- [edge](../Dockerfile) - [v1.2.1-slim, v1.2-slim, v1-slim, slim](https://github.com/drakkan/sftpgo/blob/v1.2.1/Dockerfile)
- [edge-alpine](../Dockerfile.alpine) - [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 ## 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 ### 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 ```shell
docker exec -it some-sftpgo bash docker exec -it some-sftpgo sh
``` ```
The logs are available through Docker's container log: The logs are available through Docker's container log:
@@ -98,6 +102,15 @@ docker run --name some-sftpgo \
-d "drakkan/sftpgo:tag" -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 ## 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. 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. 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 ## 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). 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).

View 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
View 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 "$@"

View File

@@ -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 - `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. - `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. - `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: - `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 - 0, disabled
- 1, enabled. Proxy header will be used and requests without proxy header will be accepted - 1, enabled. Proxy header will be used and requests without proxy header will be accepted

View File

@@ -20,9 +20,8 @@ The configured bucket must exist.
Some SFTP commands don't work over S3: Some SFTP commands don't work over S3:
- `symlink` and `chtimes` will fail - `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
- `chown` and `chmod` are silently ignored - `truncate`, `symlink`, `readlink` are not supported
- `truncate` is not supported
- opening a file for both reading and writing at the same time is not supported - opening a file for both reading and writing at the same time is not supported
- upload resume is not supported - upload resume is not supported
- upload mode `atomic` is ignored since S3 uploads are already atomic - upload mode `atomic` is ignored since S3 uploads are already atomic

27
go.mod
View File

@@ -3,12 +3,12 @@ module github.com/drakkan/sftpgo
go 1.14 go 1.14
require ( 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 cloud.google.com/go/storage v1.12.0
github.com/Azure/azure-storage-blob-go v0.11.0 github.com/Azure/azure-storage-blob-go v0.11.0
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962
github.com/alexedwards/argon2id v0.0.0-20200802152012-2464efd3196b 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/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
github.com/eikenb/pipeat v0.0.0-20200430215831-470df5986b6d github.com/eikenb/pipeat v0.0.0-20200430215831-470df5986b6d
github.com/fclairamb/ftpserverlib v0.9.1-0.20201105003045-1edd6bf7ae53 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/go-sql-driver/mysql v1.5.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/grandcat/zeroconf v1.0.0 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/lib/pq v1.8.0
github.com/magiconair/properties v1.8.4 // indirect github.com/magiconair/properties v1.8.4 // indirect
github.com/mattn/go-sqlite3 v1.14.4 github.com/mattn/go-sqlite3 v1.14.4
@@ -29,9 +29,11 @@ require (
github.com/pires/go-proxyproto v0.3.1 github.com/pires/go-proxyproto v0.3.1
github.com/pkg/sftp v1.12.1-0.20201002132022-fcaa492add82 github.com/pkg/sftp v1.12.1-0.20201002132022-fcaa492add82
github.com/prometheus/client_golang v1.8.0 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/cors v1.7.1-0.20200626170627-8b4a00bd362b
github.com/rs/xid v1.2.1 github.com/rs/xid v1.2.1
github.com/rs/zerolog v1.20.0 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/afero v1.4.1
github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.1.1 github.com/spf13/cobra v1.1.1
@@ -41,22 +43,21 @@ require (
github.com/studio-b12/gowebdav v0.0.0-20200303150724-9380631c29a1 github.com/studio-b12/gowebdav v0.0.0-20200303150724-9380631c29a1
go.etcd.io/bbolt v1.3.5 go.etcd.io/bbolt v1.3.5
go.uber.org/automaxprocs v1.3.0 go.uber.org/automaxprocs v1.3.0
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 // indirect
golang.org/x/text v0.3.4 // indirect golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba
golang.org/x/tools v0.0.0-20201105220310-78b158585360 // indirect golang.org/x/tools v0.0.0-20201113202037-1643af1435f3 // indirect
google.golang.org/api v0.35.0 google.golang.org/api v0.35.0
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20201106154455-f9bfe239b0ba // indirect google.golang.org/genproto v0.0.0-20201113130914-ce600e9a6f9e // indirect
google.golang.org/grpc v1.33.2 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0
) )
replace ( 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 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/crypto => github.com/drakkan/crypto v0.0.0-20201114074711-d051624c4fd2
golang.org/x/net => github.com/drakkan/net v0.0.0-20201104142514-34ad2afe5beb golang.org/x/net => github.com/drakkan/net v0.0.0-20201114074615-8a2467084c77
) )

46
go.sum
View File

@@ -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.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 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.66.0/go.mod h1:dgqGAjKCDxyhGTtC9dAREQGUJpkceNm1yt590Qno0Ko=
cloud.google.com/go v0.71.0 h1:2ha722Z08cmRa0orJrzBaszYQcLbLFcsZHsGSj/kIF4= cloud.google.com/go v0.72.0 h1:eWRCuwubtDrCJG0oSUMgnsbD4CmPFQF2ei4OFbXvwww=
cloud.google.com/go v0.71.0/go.mod h1:qZfY4Y7AEIQwG/fQYD3xrxLNkQZ0Xzf3HGeqCkA6LVM= 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.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.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 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/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-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.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.28 h1:S2LuRnfC8X05zgZLC8gy/Sb82TGv2Cpytzbzz7tkeHc=
github.com/aws/aws-sdk-go v1.35.23/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= 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/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 v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/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/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/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-20201114074711-d051624c4fd2 h1:1X+tt8X6lyGWn17TJaKOybGkRuGm1Rd0ErPhIY1Zy4A=
github.com/drakkan/crypto v0.0.0-20201017144935-4e8324213ac3/go.mod h1:v3bhWOXGYda7H5d2s5t9XA6th3fxW3s0MQxU1R96G/w= github.com/drakkan/crypto v0.0.0-20201114074711-d051624c4fd2/go.mod h1:v3bhWOXGYda7H5d2s5t9XA6th3fxW3s0MQxU1R96G/w=
github.com/drakkan/ftp v0.0.0-20200730125632-b21eac28818c h1:QSXIWohSNn0negBVSKEjKTpdpGEsW7weVW8QNzviLHY= github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 h1:LPH1dEblAOO/LoG7yHPMtBLXhQmjaga91/DDjWk9jWA=
github.com/drakkan/ftp v0.0.0-20200730125632-b21eac28818c/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU= github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
github.com/drakkan/net v0.0.0-20201104142514-34ad2afe5beb h1:NgZ7GvppCYwS8iG+zcuQvzVCAvTQLtxVe7PSWxJtxhI= github.com/drakkan/net v0.0.0-20201114074615-8a2467084c77 h1:keiJPG0lodjq5Ep9XuDKGRQRC52pp/8NB8/1xbqmw+Y=
github.com/drakkan/net v0.0.0-20201104142514-34ad2afe5beb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 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 h1:9rug3vpr/986h/KeITYQQx78DErOAkOes+ktVRyTPQQ=
github.com/drakkan/sftp v0.0.0-20201105171632-4ab2ef794ae3/go.mod h1:fUqqXB5vEgVCZ131L+9say31RAri6aF6KDViawhxKK8= 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= 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.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= 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.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.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-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-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 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/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 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo= 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.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/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/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/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/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/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.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 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-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-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-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-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-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-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/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-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-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-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf h1:kt3wY1Lu5MJAnKTfoMR52Cu4gwvna4VTzNOiT8tY73s= golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba h1:xmhUJGQGbxlod18iJGqVEp9cHIPLl7QiX2aA3to708s=
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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.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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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-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-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-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-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201105220310-78b158585360/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-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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.31.0/go.mod h1:CL+9IBCa2WWU6gRuBWaKqGWLFFwbEUXkfeMkHLQWYWo= 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.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 h1:TBCmTTxUrRDA1iTctnK/fIeitxIZ+TQuaf0j29fmCGo=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 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-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-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-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-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201106154455-f9bfe239b0ba h1:HocWKLuilwaaLY56cHV38rw84wJ1nscA0Rs7OnO8mm8= google.golang.org/genproto v0.0.0-20201113130914-ce600e9a6f9e h1:jRAe+6EDD0LNrVzmjx7FxBivivOZTKnXMbH5lvmxLP8=
google.golang.org/genproto v0.0.0-20201106154455-f9bfe239b0ba/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 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.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.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= 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.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.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.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 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 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= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=

View File

@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
NFPM_VERSION=1.9.0 NFPM_VERSION=1.10.1
NFPM_ARCH=${NFPM_ARCH:-amd64} NFPM_ARCH=${NFPM_ARCH:-amd64}
if [ -z ${SFTPGO_VERSION} ] if [ -z ${SFTPGO_VERSION} ]
then then
@@ -18,6 +18,7 @@ cd dist
BASE_DIR="../.." BASE_DIR="../.."
cp ${BASE_DIR}/sftpgo.json . 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|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|\"users_base_dir\": \"\",|\"users_base_dir\": \"/srv/sftpgo/data\",|" sftpgo.json
sed -i "s|\"templates\"|\"/usr/share/sftpgo/templates\"|" 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" ./sftpgo-completion.bash: "/usr/share/bash-completion/completions/sftpgo"
./man1/*: "/usr/share/man/man1/" ./man1/*: "/usr/share/man/man1/"
${BASE_DIR}/init/sftpgo.service: "/lib/systemd/system/sftpgo.service" ${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}/templates/*: "/usr/share/sftpgo/templates/"
${BASE_DIR}/static/**/*: "/usr/share/sftpgo/static/" ${BASE_DIR}/static/**/*: "/usr/share/sftpgo/static/"
@@ -67,9 +68,10 @@ overrides:
deb: deb:
recommends: recommends:
- bash-completion - bash-completion
- mime-support
suggests:
- python3-requests - python3-requests
- python3-pygments - python3-pygments
- mime-support
scripts: scripts:
postinstall: ../scripts/deb/postinstall.sh postinstall: ../scripts/deb/postinstall.sh
preremove: ../scripts/deb/preremove.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 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 tar xvf nfpm_${NFPM_VERSION}_Linux_x86_64.tar.gz nfpm
chmod 755 nfpm chmod 755 nfpm
mkdir deb
./nfpm -f nfpm.yaml pkg -p deb -t deb
mkdir rpm mkdir rpm
./nfpm -f nfpm.yaml pkg -p rpm -t 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

View File

@@ -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 sftpgo (1.1.1-1ppa2) bionic; urgency=medium
* Fix sftpgo data dir. * Fix sftpgo data dir.

View File

@@ -10,7 +10,8 @@ Vcs-Git: https://github.com/drakkan/sftpgo.git
Package: sftpgo Package: sftpgo
Architecture: amd64 Architecture: amd64
Depends: ${shlibs:Depends}, ${misc:Depends} 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 Description: Fully featured and highly configurable SFTP server
SFTPGo has optional FTP/S and WebDAV support. SFTPGo has optional FTP/S and WebDAV support.
It can serve local filesystem, S3 (Compatible) Object Storage, It can serve local filesystem, S3 (Compatible) Object Storage,

View File

@@ -2,7 +2,7 @@ Index: sftpgo/sftpgo.json
=================================================================== ===================================================================
--- sftpgo.orig/sftpgo.json --- sftpgo.orig/sftpgo.json
+++ sftpgo/sftpgo.json +++ sftpgo/sftpgo.json
@@ -69,7 +69,7 @@ @@ -74,7 +74,7 @@
}, },
"data_provider": { "data_provider": {
"driver": "sqlite", "driver": "sqlite",
@@ -11,7 +11,7 @@ Index: sftpgo/sftpgo.json
"host": "", "host": "",
"port": 5432, "port": 5432,
"username": "", "username": "",
@@ -80,14 +80,14 @@ @@ -85,14 +85,14 @@
"manage_users": 1, "manage_users": 1,
"track_quota": 2, "track_quota": 2,
"pool_size": 0, "pool_size": 0,
@@ -25,10 +25,10 @@ Index: sftpgo/sftpgo.json
"external_auth_scope": 0, "external_auth_scope": 0,
- "credentials_path": "credentials", - "credentials_path": "credentials",
+ "credentials_path": "/var/lib/sftpgo/credentials", + "credentials_path": "/var/lib/sftpgo/credentials",
"prefer_database_credentials": false,
"pre_login_hook": "", "pre_login_hook": "",
"post_login_hook": "", "post_login_hook": "",
"post_login_scope": 0, @@ -111,9 +111,9 @@
@@ -105,9 +105,9 @@
"httpd": { "httpd": {
"bind_port": 8080, "bind_port": 8080,
"bind_address": "127.0.0.1", "bind_address": "127.0.0.1",
@@ -41,10 +41,3 @@ Index: sftpgo/sftpgo.json
"auth_user_file": "", "auth_user_file": "",
"certificate_file": "", "certificate_file": "",
"certificate_key_file": "" "certificate_key_file": ""
@@ -117,4 +117,4 @@
"ca_certificates": [],
"skip_tls_verify": false
}
-}
\ No newline at end of file
+}

View File

@@ -397,17 +397,6 @@ func TestSFTPCmdTargetPath(t *testing.T) {
assert.True(t, os.IsNotExist(err)) 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) { func TestSFTPGetUsedQuota(t *testing.T) {
u := dataprovider.User{} u := dataprovider.User{}
u.HomeDir = "home_rel_path" u.HomeDir = "home_rel_path"
@@ -1680,6 +1669,13 @@ func TestTransferFailingReader(t *testing.T) {
err = tr.Close() err = tr.Close()
assert.NoError(t, err) 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) err = os.Remove(fsPath)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, connection.GetTransfers(), 0) assert.Len(t, connection.GetTransfers(), 0)

View File

@@ -32,6 +32,9 @@ func (r *failingReader) ReadAt(p []byte, off int64) (n int, err error) {
} }
func (r *failingReader) Close() error { func (r *failingReader) Close() error {
if r.innerReader == nil {
return nil
}
return r.innerReader.Close() 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{ return &transfer{
BaseTransfer: baseTransfer, BaseTransfer: baseTransfer,
writerAt: writer, writerAt: writer,

View File

@@ -2,7 +2,7 @@ package version
import "strings" import "strings"
const version = "1.2.0" const version = "1.2.1"
var ( var (
commit = "" commit = ""

View File

@@ -361,37 +361,34 @@ func (fs *AzureBlobFs) Mkdir(name string) error {
// Symlink creates source as a symbolic link to target. // Symlink creates source as a symbolic link to target.
func (*AzureBlobFs) Symlink(source, target string) error { 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 // Readlink returns the destination of the named symbolic link
func (*AzureBlobFs) Readlink(name string) (string, error) { 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. // Chown changes the numeric uid and gid of the named file.
// Silently ignored.
func (*AzureBlobFs) Chown(name string, uid int, gid int) error { func (*AzureBlobFs) Chown(name string, uid int, gid int) error {
return nil return ErrVfsUnsupported
} }
// Chmod changes the mode of the named file to mode. // Chmod changes the mode of the named file to mode.
// Silently ignored.
func (*AzureBlobFs) Chmod(name string, mode os.FileMode) error { func (*AzureBlobFs) Chmod(name string, mode os.FileMode) error {
return nil return ErrVfsUnsupported
} }
// Chtimes changes the access and modification times of the named file. // Chtimes changes the access and modification times of the named file.
// Silently ignored.
func (*AzureBlobFs) Chtimes(name string, atime, mtime time.Time) error { 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 changes the size of the named file.
// Truncate by path is not supported, while truncating an opened // Truncate by path is not supported, while truncating an opened
// file is handled inside base transfer // file is handled inside base transfer
func (*AzureBlobFs) Truncate(name string, size int64) error { 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 // 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") 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 // CheckRootPath creates the specified local root directory if it does not exists
func (fs *AzureBlobFs) CheckRootPath(username string, uid int, gid int) bool { func (fs *AzureBlobFs) CheckRootPath(username string, uid int, gid int) bool {
// we need a local directory for temporary files // 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 // GetDirSize returns the number of files and the size for a folder
// including any subfolders // including any subfolders
func (*AzureBlobFs) GetDirSize(dirname string) (int, int64, error) { 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. // GetAtomicUploadPath returns the path to use for an atomic upload.

View File

@@ -218,8 +218,12 @@ func (fs *GCSFs) Create(name string, flag int) (*os.File, *PipeWriter, func(), e
} }
go func() { go func() {
defer cancelFn() defer cancelFn()
defer objectWriter.Close()
n, err := io.Copy(objectWriter, r) n, err := io.Copy(objectWriter, r)
closeErr := objectWriter.Close()
if err == nil {
err = closeErr
}
r.CloseWithError(err) //nolint:errcheck r.CloseWithError(err) //nolint:errcheck
p.Done(err) p.Done(err)
fsLog(fs, logger.LevelDebug, "upload completed, path: %#v, readed bytes: %v, err: %v", name, n, 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. // Symlink creates source as a symbolic link to target.
func (*GCSFs) Symlink(source, target string) error { 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 // Readlink returns the destination of the named symbolic link
func (*GCSFs) Readlink(name string) (string, error) { 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. // Chown changes the numeric uid and gid of the named file.
// Silently ignored.
func (*GCSFs) Chown(name string, uid int, gid int) error { func (*GCSFs) Chown(name string, uid int, gid int) error {
return nil return ErrVfsUnsupported
} }
// Chmod changes the mode of the named file to mode. // Chmod changes the mode of the named file to mode.
// Silently ignored.
func (*GCSFs) Chmod(name string, mode os.FileMode) error { func (*GCSFs) Chmod(name string, mode os.FileMode) error {
return nil return ErrVfsUnsupported
} }
// Chtimes changes the access and modification times of the named file. // Chtimes changes the access and modification times of the named file.
// Silently ignored.
func (*GCSFs) Chtimes(name string, atime, mtime time.Time) error { 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 changes the size of the named file.
// Truncate by path is not supported, while truncating an opened // Truncate by path is not supported, while truncating an opened
// file is handled inside base transfer // file is handled inside base transfer
func (*GCSFs) Truncate(name string, size int64) error { 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 // 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") 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 // CheckRootPath creates the specified local root directory if it does not exists
func (fs *GCSFs) CheckRootPath(username string, uid int, gid int) bool { func (fs *GCSFs) CheckRootPath(username string, uid int, gid int) bool {
// we need a local directory for temporary files // 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 // GetDirSize returns the number of files and the size for a folder
// including any subfolders // including any subfolders
func (*GCSFs) GetDirSize(dirname string) (int, int64, error) { 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. // GetAtomicUploadPath returns the path to use for an atomic upload.

View File

@@ -185,6 +185,14 @@ func (*OsFs) IsPermission(err error) bool {
return os.IsPermission(err) 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 // CheckRootPath creates the root directory if it does not exists
func (fs *OsFs) CheckRootPath(username string, uid int, gid int) bool { func (fs *OsFs) CheckRootPath(username string, uid int, gid int) bool {
var err error var err error

View File

@@ -350,37 +350,34 @@ func (fs *S3Fs) Mkdir(name string) error {
// Symlink creates source as a symbolic link to target. // Symlink creates source as a symbolic link to target.
func (*S3Fs) Symlink(source, target string) error { 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 // Readlink returns the destination of the named symbolic link
func (*S3Fs) Readlink(name string) (string, error) { 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. // Chown changes the numeric uid and gid of the named file.
// Silently ignored.
func (*S3Fs) Chown(name string, uid int, gid int) error { func (*S3Fs) Chown(name string, uid int, gid int) error {
return nil return ErrVfsUnsupported
} }
// Chmod changes the mode of the named file to mode. // Chmod changes the mode of the named file to mode.
// Silently ignored.
func (*S3Fs) Chmod(name string, mode os.FileMode) error { func (*S3Fs) Chmod(name string, mode os.FileMode) error {
return nil return ErrVfsUnsupported
} }
// Chtimes changes the access and modification times of the named file. // Chtimes changes the access and modification times of the named file.
// Silently ignored.
func (*S3Fs) Chtimes(name string, atime, mtime time.Time) error { 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 changes the size of the named file.
// Truncate by path is not supported, while truncating an opened // Truncate by path is not supported, while truncating an opened
// file is handled inside base transfer // file is handled inside base transfer
func (*S3Fs) Truncate(name string, size int64) error { 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 // 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") 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 // CheckRootPath creates the specified local root directory if it does not exists
func (fs *S3Fs) CheckRootPath(username string, uid int, gid int) bool { func (fs *S3Fs) CheckRootPath(username string, uid int, gid int) bool {
// we need a local directory for temporary files // 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 // GetDirSize returns the number of files and the size for a folder
// including any subfolders // including any subfolders
func (*S3Fs) GetDirSize(dirname string) (int, int64, error) { 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. // GetAtomicUploadPath returns the path to use for an atomic upload.

View File

@@ -46,6 +46,7 @@ type Fs interface {
ResolvePath(sftpPath string) (string, error) ResolvePath(sftpPath string) (string, error)
IsNotExist(err error) bool IsNotExist(err error) bool
IsPermission(err error) bool IsPermission(err error) bool
IsNotSupported(err error) bool
ScanRootDirContents() (int, int64, error) ScanRootDirContents() (int, int64, error)
GetDirSize(dirname string) (int, int64, error) GetDirSize(dirname string) (int, int64, error)
GetAtomicUploadPath(name string) string GetAtomicUploadPath(name string) string
@@ -56,7 +57,8 @@ type Fs interface {
GetMimeType(name string) (string, error) 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 // QuotaCheckResult defines the result for a quota check
type QuotaCheckResult struct { type QuotaCheckResult struct {