Change docker user and some minor improvements

This commit is contained in:
Xiaonan Shen
2022-05-28 17:28:20 +08:00
parent c38ac6fbb5
commit 1c64b99201
6 changed files with 125 additions and 52 deletions

View File

@@ -11,7 +11,7 @@ COPY build.sh /build/
COPY http_rest_frontend /build/http_rest_frontend COPY http_rest_frontend /build/http_rest_frontend
RUN bash build.sh RUN bash build.sh
FROM ubuntu:bionic FROM krallin/ubuntu-tini:bionic
LABEL maintainer="Xiaonan Shen <s@sxn.dev>" LABEL maintainer="Xiaonan Shen <s@sxn.dev>"
EXPOSE 25/tcp EXPOSE 25/tcp
@@ -19,13 +19,15 @@ EXPOSE 143/tcp
# Install dependencies and protonmail bridge # Install dependencies and protonmail bridge
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends socat pass libsecret-1-0 ca-certificates dbus-x11 \ && apt-get install -y --no-install-recommends socat pass libsecret-1-0 ca-certificates curl gosu \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Copy bash scripts # Copy bash scripts
COPY gpgparams entrypoint.sh /srv/protonmail/ COPY gpgparams entrypoint.sh run_protonmail_bridge.sh cli.sh /protonmail/bin/
# Copy protonmail # Copy protonmail
COPY --from=build /build/proton-bridge/proton-bridge /srv/protonmail/ COPY --from=build /build/proton-bridge/proton-bridge /protonmail/bin
ENV PATH "/protonmail/bin:${PATH}"
ENTRYPOINT ["bash", "/srv/protonmail/entrypoint.sh"] VOLUME [ "/protonmail/data" ]
ENTRYPOINT ["/usr/local/bin/tini", "--", "/protonmail/bin/entrypoint.sh"]

6
cli.sh
View File

@@ -2,7 +2,7 @@
set -e set -e
URL_BASE=http://127.0.0.1:1080 URL_BASE=http://127.0.0.1:${PROTON_MANAGEMENT_PORT:-1080}
print_help() { print_help() {
echo "Available commands:" echo "Available commands:"
@@ -24,12 +24,14 @@ account_login() {
echo echo
read -p "2FA Code (leave empty if not set): " TWO_FACTOR read -p "2FA Code (leave empty if not set): " TWO_FACTOR
read -p "Mailbox Password (leave empty if not set): " MAILBOX_PASSWORD read -p "Mailbox Password (leave empty if not set): " MAILBOX_PASSWORD
read -p "Address Mode (combined / split): " ADDRESS_MODE
curl ${URL_BASE}/accounts -XPUT \ curl ${URL_BASE}/accounts -XPUT \
--data-urlencode "username=${USERNAME}" \ --data-urlencode "username=${USERNAME}" \
--data-urlencode "password=${PASSWORD}" \ --data-urlencode "password=${PASSWORD}" \
--data-urlencode "two-factor=${TWO_FACTOR}" \ --data-urlencode "two-factor=${TWO_FACTOR}" \
--data-urlencode "mailbox-password=${MAILBOX_PASSWORD}" --data-urlencode "mailbox-password=${MAILBOX_PASSWORD}" \
--data-urlencode "address-mode=${ADDRESS_MODE}"
} }
account_delete() { account_delete() {

41
entrypoint.sh Normal file → Executable file
View File

@@ -2,36 +2,15 @@
set -e set -e
# Generate gpg keys echo "Welcome to ProtonMail Bridge Docker 2.0. This version comes with plently of"
if [ ! -f ${HOME}/.gnupg ]; then echo "improvements. This version is not compatible with old configs and data volumes."
echo "Generateing gpg keys..." echo "If you are coming from the old version, please clean up your volumes and set up"
# set GNUPGHOME as a workaround for echo "everything from scratch. For more information about the new version, check"
# echo "https://github.com/shenxn/protonmail-bridge-docker"
# gpg-agent[106]: error binding socket to '/root/.gnupg/S.gpg-agent': File name too long echo
#
# when using docker volume mount
#
# ref: https://dev.gnupg.org/T2964
#
export GNUPGHOME=/tmp/gnupg
mkdir ${GNUPGHOME}
chmod 700 ${GNUPGHOME}
gpg --generate-key --batch /srv/protonmail/gpgparams
pkill gpg-agent
mv ${GNUPGHOME} ${HOME}/.gnupg
export GNUPGHOME=""
fi
# Initialize pass groupadd -g ${PROTON_GID:-1001} proton
if [ ! -f ${HOME}/.password-store/.gpg-id ]; then useradd -g proton -u ${PROTON_UID:-1001} -m proton
echo "Initializing pass" chown proton:proton -R /protonmail/data
pass init pass-key
fi
# socat will make the conn appear to come from 127.0.0.1 exec gosu proton:proton run_protonmail_bridge.sh "$@"
# ProtonMail Bridge currently expects that.
# It also allows us to bind to the real ports :)
socat TCP-LISTEN:25,fork TCP:127.0.0.1:1025 &
socat TCP-LISTEN:143,fork TCP:127.0.0.1:1143 &
/srv/protonmail/proton-bridge --cli $@

View File

@@ -6,11 +6,13 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"os"
"strings" "strings"
"github.com/ProtonMail/proton-bridge/internal/config/settings" "github.com/ProtonMail/proton-bridge/internal/config/settings"
"github.com/ProtonMail/proton-bridge/internal/frontend/types" "github.com/ProtonMail/proton-bridge/internal/frontend/types"
"github.com/julienschmidt/httprouter" "github.com/julienschmidt/httprouter"
"github.com/sirupsen/logrus"
) )
func (f *frontendCLI) loginAccount(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { func (f *frontendCLI) loginAccount(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
@@ -23,33 +25,38 @@ func (f *frontendCLI) loginAccount(w http.ResponseWriter, r *http.Request, _ htt
password := r.FormValue("password") password := r.FormValue("password")
twoFactor := r.FormValue("two-factor") twoFactor := r.FormValue("two-factor")
mailboxPassword := r.FormValue("mailbox-password") mailboxPassword := r.FormValue("mailbox-password")
addressMode := r.FormValue("address-mode")
if addressMode == "" {
addressMode = "combined"
}
if addressMode != "combined" && addressMode != "split" {
http.Error(w, fmt.Sprintf("%s is not a valid address mode. Choose from 'combined' and 'split'."), http.StatusBadRequest)
return
}
client, auth, err := f.bridge.Login(username, []byte(password)) client, auth, err := f.bridge.Login(username, []byte(password))
if err != nil { if err != nil {
f.processAPIError(err) f.processAPIError(err)
w.WriteHeader(http.StatusUnauthorized) http.Error(w, fmt.Sprintf("Server error: %s", err.Error()), http.StatusUnauthorized)
fmt.Fprintln(w, "Server error:", err.Error())
return return
} }
if auth.HasTwoFactor() { if auth.HasTwoFactor() {
if twoFactor == "" { if twoFactor == "" {
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
fmt.Fprintln(w, "2FA enabled for the account but a 2FA code was not provided.") http.Error(w, "2FA enabled for the account but a 2FA code was not provided.", http.StatusUnauthorized)
return return
} }
err = client.Auth2FA(context.Background(), twoFactor) err = client.Auth2FA(context.Background(), twoFactor)
if err != nil { if err != nil {
f.processAPIError(err) f.processAPIError(err)
w.WriteHeader(http.StatusUnauthorized) http.Error(w, fmt.Sprintf("Server error: %s", err.Error()), http.StatusUnauthorized)
fmt.Fprintln(w, "Server error:", err.Error())
return return
} }
} }
if auth.HasMailboxPassword() { if auth.HasMailboxPassword() {
if mailboxPassword == "" { if mailboxPassword == "" {
w.WriteHeader(http.StatusUnauthorized) http.Error(w, "Two password mode enabled but a mailbox password was not provided.", http.StatusUnauthorized)
fmt.Fprintln(w, "Two password mode enabled but a mailbox password was not provided.")
return return
} }
} else { } else {
@@ -58,11 +65,20 @@ func (f *frontendCLI) loginAccount(w http.ResponseWriter, r *http.Request, _ htt
user, err := f.bridge.FinishLogin(client, auth, []byte(mailboxPassword)) user, err := f.bridge.FinishLogin(client, auth, []byte(mailboxPassword))
if err != nil { if err != nil {
f.processAPIError(err) f.processAPIError(err)
w.WriteHeader(http.StatusUnauthorized) http.Error(w, fmt.Sprintf("Server error: %s", err.Error()), http.StatusUnauthorized)
fmt.Fprintln(w, "Server error:", err.Error())
return return
} }
fmt.Fprintf(w, "Account %s was added successfully.\n", user.Username()) fmt.Fprintf(w, "Account %s was added successfully.\n", user.Username())
if addressMode == "split" {
err = user.SwitchAddressMode()
if err != nil {
logrus.Errorf("Failed to switch address mode of %s to split: %s", user.Username(), err.Error())
http.Error(w, "Failed to switch address mode to split", http.StatusInternalServerError)
return
}
}
f.printAccountInfo(w, user) f.printAccountInfo(w, user)
} }
@@ -135,10 +151,10 @@ func (f *frontendCLI) printAccountAddressInfo(w io.Writer, user types.User, addr
if f.settings.GetBool(settings.SMTPSSLKey) { if f.settings.GetBool(settings.SMTPSSLKey) {
smtpSecurity = "SSL" smtpSecurity = "SSL"
} }
fmt.Fprintf(w, "IMAP port: %d\nIMAP security: %s\nSMTP port: %d\nSMTP security: %s\nUsername: %s\nPassword: %s\n", fmt.Fprintf(w, "IMAP port: %s\nIMAP security: %s\nSMTP port: %s\nSMTP security: %s\nUsername: %s\nPassword: %s\n",
143, os.Getenv("PROTON_IMAP_PORT"),
"STARTTLS", "STARTTLS",
25, os.Getenv("PROTON_SMTP_PORT"),
smtpSecurity, smtpSecurity,
address, address,
user.GetBridgePassword(), user.GetBridgePassword(),

View File

@@ -146,7 +146,11 @@ func (f *frontendCLI) watchEvents() {
func (f *frontendCLI) Loop() error { func (f *frontendCLI) Loop() error {
f.loginWithEnv() f.loginWithEnv()
http.ListenAndServe(":1080", f) managementPort := os.Getenv("PROTON_MANAGEMENT_PORT")
if managementPort == "" {
managementPort = "1080"
}
http.ListenAndServe(":"+managementPort, f)
return nil return nil
} }

70
run_protonmail_bridge.sh Executable file
View File

@@ -0,0 +1,70 @@
#!/bin/bash
set -e
# Generate gpg keys
GNUPG_PATH=/protonmail/data/gnupg
export GNUPGHOME=${GNUPG_PATH}
if [ ! -f ${GNUPG_PATH} ]; then
echo "Generateing gpg keys..."
# set GNUPGHOME to a temp directory as a workaround for
#
# gpg-agent[106]: error binding socket to '/root/.gnupg/S.gpg-agent': File name too long
#
# when using docker volume mount
#
# ref: https://dev.gnupg.org/T2964
#
export GNUPGHOME=/tmp/gnupg
mkdir ${GNUPGHOME}
chmod 700 ${GNUPGHOME}
gpg --generate-key --batch /protonmail/bin/gpgparams
pkill gpg-agent
mv ${GNUPGHOME} ${GNUPG_PATH}
export GNUPGHOME=${GNUPG_PATH}
fi
# Initialize pass
PASSWORD_STORE=/protonmail/data/password-store
if [ ! -f ${PASSWORD_STORE} ]; then
echo "Initializing pass..."
pass init pass-key
# Move password store to /protonmail/data
mv ${HOME}/.password-store ${PASSWORD_STORE}
fi
# Link the password store back to ~/.password-store
# There is no easy way to change the path used by pass
ln -s ${PASSWORD_STORE} ${HOME}/.password-store
# Link config and cache folders to /protonmail/data
PROTON_CONFIG_PATH=/protonmail/data/config
PROTON_CACHE_PATH=/protonmail/data/cache
mkdir -p ${PROTON_CONFIG_PATH}
mkdir -p ${HOME}/.config
ln -s ${PROTON_CONFIG_PATH} ${HOME}/.config/protonmail
mkdir -p ${PROTON_CACHE_PATH}
mkdir ${HOME}/.cache
ln -s ${PROTON_CACHE_PATH} ${HOME}/.cache/protonmail
# Generateing perfs.json
mkdir -p ${PROTON_CONFIG_PATH}/bridge
if [ ${PROTON_SMTP_SECURITY:-STARTTLS} == "SSL" ]; then
PROTON_SSL_SMTP="true"
else
PROTON_SSL_SMTP="false"
fi
cat <<EOF > ${PROTON_CONFIG_PATH}/bridge/prefs.json
{
"allow_proxy": "${PROTON_ALLOW_PROXY:-true}",
"autoupdate": "false",
"user_ssl_smtp": "${PROTON_SSL_SMTP}"
}
EOF
# socat will make the conn appear to come from 127.0.0.1
# ProtonMail Bridge currently expects that.
# It also allows us to bind to the real ports :)
socat TCP-LISTEN:${PROTON_SMTP_PORT:=25},fork TCP:127.0.0.1:1025 &
socat TCP-LISTEN:${PROTON_IMAP_PORT:=143},fork TCP:127.0.0.1:1143 &
exec proton-bridge --cli "$@"