diff --git a/Develop.md b/Develop.md index 3f808b3..3b271d0 100644 --- a/Develop.md +++ b/Develop.md @@ -163,13 +163,14 @@ Here are the main application files and directories from within the images : ┃ ┗ 📂 .local/ ┃ ┣ 📂 bin/ - - - - - - - - - - - - - -> shortcuts ┃ ┃ ┣ 📜 askbot + ┃ ┃ ┣ 📜 docker-entrypoint.sh ┃ ┃ ┣ 📜 transbot ┃ ┃ ┗ 📜 ... - ┃ ┣ 📂 lib/pythonX.X/site-packages/ - -> Python packages (nicobot & dependencies) - ┃ ┗ 📂 share/signal-cli/ - - - - - - - -> signal-cli configuration files - ┗ 📂 usr/src/app/ - - - - - - - - - - - -> app's working directory, default configuration files, ... + ┃ ┗ 📂 lib/pythonX.X/site-packages/ - -> Python packages (nicobot & dependencies) + ┗ 📂 var/nicobot/ - - - - - - - - - - - -> Configuration files & data (contains secret stuff !) ┣ 📂 .omemo/ - - - - - - - - - - - - - -> OMEMO keys (XMPP) - ┣ 📜 docker-entrypoint.sh + ┣ 📂 .signal-cli/ - - - - - - - - - - -> signal-cli configuration files + ┣ 📜 config.yml ┣ 📜 i18n.en.yml ┗ 📜 ... diff --git a/alpine.Dockerfile b/alpine.Dockerfile index 73cf81c..2e917d9 100644 --- a/alpine.Dockerfile +++ b/alpine.Dockerfile @@ -75,7 +75,7 @@ RUN python3 -m pip install --no-cache-dir --user . # - glibc FROM python:3-alpine -WORKDIR /usr/src/app +WORKDIR /var/nicobot # Runtime packages requirements # @@ -85,6 +85,7 @@ RUN apk add --no-cache libressl-dev bash # Required by slixmpp-omemo plugin RUN mkdir -p .omemo +# Signal-cli also creates .signal-cli/ # Not used currently (we just copy the /root/.local directory which has everyting thanks to the --user option) #COPY --from=builder /usr/src/app/wheels ./wheels @@ -102,5 +103,6 @@ COPY --from=builder /root/.local /root/.local/ # - also adds extra command line options for Signal device linking # Otherwise the ENTRYPOINT would simply be [ "python"] # Also copying some default configuration files -COPY docker/docker-entrypoint.sh docker/default-conf/* . -ENTRYPOINT [ "./docker-entrypoint.sh" ] +COPY docker/docker-entrypoint.sh /root/.local/bin/ +COPY docker/default-conf/* . +ENTRYPOINT [ "docker-entrypoint.sh" ] diff --git a/debian.Dockerfile b/debian.Dockerfile index e353f81..af53a7f 100644 --- a/debian.Dockerfile +++ b/debian.Dockerfile @@ -57,10 +57,11 @@ RUN python3 -m pip install --no-cache-dir --user . # - glibc FROM python:3-slim -WORKDIR /usr/src/app +WORKDIR /var/nicobot # Required by slixmpp-omemo plugin RUN mkdir -p .omemo +# Signal-cli also creates .signal-cli/ # Not used currently (we just copy the /root/.local directory which has everyting thanks to the --user option) #COPY --from=builder /usr/src/app/wheels ./wheels @@ -78,5 +79,6 @@ COPY --from=builder /root/.local /root/.local/ # - also adds extra command line options for Signal device linking # Otherwise the ENTRYPOINT would simply be [ "python"] # Also copying some default configuration files -COPY docker/docker-entrypoint.sh docker/default-conf/* . -ENTRYPOINT [ "./docker-entrypoint.sh" ] +COPY docker/docker-entrypoint.sh /root/.local/bin/ +COPY docker/default-conf/* . +ENTRYPOINT [ "docker-entrypoint.sh" ] diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index b51475c..3d493ec 100755 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -34,6 +34,9 @@ EOF opt_signal_register= opt_qrcode_options= opt_bot= +SIGNALCLI_CONFIG_DIR=/var/nicobot/.signal-cli +JABBER_CONFIG_DIR=/var/nicobot/.omemo + # Parses the command line for options to execute before running the bot # TODO Enhance CLI handling with getopt @@ -70,7 +73,8 @@ fi case "${opt_bot}" in askbot|transbot) #exec python3 -m "nicobot.${opt_bot}" "$@" - exec "${opt_bot}" "$@" + # TODO Allow to override config dirs with the docker command line + exec "${opt_bot}" "--signal-config-dir" ${SIGNALCLI_CONFIG_DIR} "--jabber-config-dir" ${JABBER_CONFIG_DIR} "$@" ;; *) echo "Unknown bot : '*{opt_bot}'" >2 diff --git a/nicobot/bot.py b/nicobot/bot.py index 0c8bb43..29ae9c5 100644 --- a/nicobot/bot.py +++ b/nicobot/bot.py @@ -121,12 +121,15 @@ class ArgsHelper: recipients = args.jabber_recipients + args.recipients if len(recipients)==0: raise ValueError("Missing --jabber-recipient") + data_dir = args.jabber_config_dir + if not data_dir: + data_dir = os.path.join(args.config_dir,".omemo") # TODO allow multiple recipients return JabberChatter( jid=username, password=args.jabber_password, recipient=recipients[0], - data_dir=os.path.join(args.config_dir,".omemo") + data_dir=data_dir ) @@ -143,13 +146,17 @@ class ArgsHelper: recipients = args.signal_recipients + args.recipients if len(recipients)==0 and not args.signal_group: raise ValueError("Either --signal-recipient or --signal-group must be provided") + config_dir = args.signal_config_dir + if not config_dir: + config_dir = os.path.join(args.config_dir,".signal-cli") # TODO allow multiple recipients return SignalChatter( username=username, recipient=recipients[0], group=args.signal_group, signal_cli=args.signal_cli, - stealth=args.signal_stealth + stealth=args.signal_stealth, + config_dir=config_dir ) # TODO :timeout=args.timeout diff --git a/nicobot/jabber.py b/nicobot/jabber.py index 8ed1461..5c6bd04 100755 --- a/nicobot/jabber.py +++ b/nicobot/jabber.py @@ -338,5 +338,6 @@ def arg_parser(): parser.add_argument('--jabber-username', '--jabberid', '--jid', dest='jabber_username', help="Username when using the Jabber/XMPP backend (overrides --username)") parser.add_argument('--jabber-recipient', dest='jabber_recipients', action='append', default=[], help="Recipient when using the Jabber/XMPP backend (overrides --recipient)") parser.add_argument('--jabber-password', dest='jabber_password', help="Senders's password") + parser.add_argument('--jabber-config-dir', dest='jabber_config_dir', default=None, help='Directory where to store OMEMO keys') return parser diff --git a/nicobot/signalcli.py b/nicobot/signalcli.py index ab4a0d7..a6ad30f 100755 --- a/nicobot/signalcli.py +++ b/nicobot/signalcli.py @@ -30,7 +30,7 @@ class SignalChatter(Chatter): A signal bot relying on signal-cli """ - def __init__( self, username, recipient=None, group=None, signal_cli=shutil.which("signal-cli"), stealth=False, send_timeout=SEND_TIMEOUT, receive_timeout=RECEIVE_TIMEOUT ): + def __init__( self, username, recipient=None, group=None, signal_cli=shutil.which("signal-cli"), stealth=False, send_timeout=SEND_TIMEOUT, receive_timeout=RECEIVE_TIMEOUT, config_dir=None ): """ stealth: if True, will connect and listen to messages but instead of sending answers, will print them @@ -47,6 +47,7 @@ class SignalChatter(Chatter): self.recipient = recipient self.group = group self.signal_cli = signal_cli + self.config_dir = config_dir self.stealth = stealth if self.stealth: logging.debug("Stealth mode : will not send message") @@ -75,6 +76,8 @@ class SignalChatter(Chatter): def send( self, message ): cmd = [ self.signal_cli, "-u", self.username, "send", "-m", message ] + if self.config_dir: + cmd = cmd + [ "--config", self.config_dir ] if self.recipient: cmd = cmd + [ self.recipient ] elif self.group: @@ -109,6 +112,8 @@ class SignalChatter(Chatter): timeout = self.receive_timeout cmd = [ self.signal_cli, "-u", self.username, "receive", "--json" ] + if self.config_dir: + cmd = cmd + [ "--config", self.config_dir ] if timeout: cmd = cmd + [ "-t", str(timeout) ] @@ -191,5 +196,6 @@ class ArgsHelper: parser.add_argument('--signal-group', dest='signal_group', help="Group's ID (for Signal : a base64 string (e.g. 'mPC9JNVoKDGz0YeZMsbL1Q==')") parser.add_argument('--signal-recipient', dest='signal_recipients', action='append', default=[], help="Recipient when using the Signal backend (overrides --recipient)") parser.add_argument('--signal-stealth', dest='signal_stealth', action="store_true", default=self.signal_stealth, help="Activate Signal chatter's specific stealth mode") + parser.add_argument('--signal-config-dir', dest='signal_config_dir', default=None, help="Directory where to store Signal configuration and sensitive data") return parser