summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKali Kaneko <kali@leap.se>2015-09-24 15:09:58 -0400
committerKali Kaneko <kali@leap.se>2015-09-24 15:09:58 -0400
commit08694af26b7b3d2e480c8379745dd5234315c87d (patch)
treeb38ce71cc7073bb573db97ca0dfc0c6ba0aa860f
parentddc30afd194bb31a24cf5097fba8680721834b1f (diff)
parentaa31828fca8bb64ace56f6f3b2b94f90ffced3c2 (diff)
Merge tag '0.9.0rc3' into debian/experimental
Tag leap.bitmask version 0.9.0rc3
-rw-r--r--.gitignore2
-rw-r--r--CHANGELOG.rst20
-rw-r--r--Makefile1
-rw-r--r--README.rst5
-rw-r--r--docker/Dockerfile32
-rw-r--r--docker/README.rst49
-rwxr-xr-xdocker/bitmask-docker.sh116
-rw-r--r--docker/bitmask-nightly.json11
-rwxr-xr-xdocker/debian/apt-bitmask.sh122
-rwxr-xr-xdocker/debian/bitmask-on-docker.sh23
-rw-r--r--docker/debian/leap-experimental.key52
-rwxr-xr-xdocker/debian/run-docker-for-bitmask.sh22
-rwxr-xr-xdocker/leap_bootstrap.sh320
-rw-r--r--docs/man/bitmask-root.1.rst4
-rw-r--r--pkg/leap_versions.txt8
-rw-r--r--pkg/requirements.pip3
-rw-r--r--setup.cfg4
-rw-r--r--src/leap/bitmask/app.py1
-rw-r--r--src/leap/bitmask/backend/backend_proxy.py21
-rw-r--r--src/leap/bitmask/crypto/certs.py38
-rw-r--r--src/leap/bitmask/crypto/srpauth.py22
-rw-r--r--src/leap/bitmask/gui/account.py4
-rw-r--r--src/leap/bitmask/gui/app.py2
-rw-r--r--src/leap/bitmask/gui/eip_status.py3
-rw-r--r--src/leap/bitmask/gui/login.py6
-rw-r--r--src/leap/bitmask/gui/mail_status.py44
-rw-r--r--src/leap/bitmask/gui/mainwindow.py48
-rw-r--r--src/leap/bitmask/gui/passwordwindow.py13
-rw-r--r--src/leap/bitmask/gui/preferenceswindow.py2
-rw-r--r--src/leap/bitmask/logs/utils.py3
-rw-r--r--src/leap/bitmask/services/mail/imapcontroller.py15
-rw-r--r--src/leap/bitmask/services/mail/smtpbootstrapper.py29
-rw-r--r--src/leap/bitmask/services/mail/smtpconfig.py7
-rw-r--r--src/leap/bitmask/updater.py4
-rw-r--r--src/leap/bitmask/util/__init__.py3
-rw-r--r--src/leap/bitmask/util/pastebin.py8
36 files changed, 980 insertions, 87 deletions
diff --git a/.gitignore b/.gitignore
index 23bfbfe8..62b21fd1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,3 +37,5 @@ CHANGELOG~
data/bitmask.pro
bitmask-resources.png
+
+docker/data
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 952574dc..2114c5ab 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -3,6 +3,26 @@
Changelog
---------
+0.9.0rc3 September 22
++++++++++++++++++++++
+
+Features
+~~~~~~~~
+- `#4284 <https://leap.se/code/issues/4284>`_: Download specific smtp certificate from provider, instead of using the vpn one.
+- `#7414 <https://leap.se/code/issues/7414>`_: Remove taskthread dependency, replace with custom (and small) code.
+- `#7419 <https://leap.se/code/issues/7419>`_: Load credentials from environment variables and trigger login.
+
+
+Bugfixes
+~~~~~~~~
+- `#7415 <https://leap.se/code/issues/7415>`_: Fix wrong argument number on window raise event.
+- `#7448 <https://leap.se/code/issues/7448>`_: Fix hangs during logout.
+- `#7453 <https://leap.se/code/issues/7453>`_: After a complete sync show the user the amount of unread emails.
+- `#7470 <https://leap.se/code/issues/7470>`_: Fix bug with password change.
+- `#7474 <https://leap.se/code/issues/7474>`_: Track soledad ready state on a shared place for easy access. Enable password change window.
+- Authenticate properly logout calls to API.
+
+
0.9.0rc2 August 27
++++++++++++++++++
diff --git a/Makefile b/Makefile
index 7d7c8e23..5fea9387 100644
--- a/Makefile
+++ b/Makefile
@@ -135,6 +135,7 @@ pull_leapdeps:
checkout_leapdeps_develop:
for repo in $(LEAP_REPOS); do cd $(CURDIR)/../$$repo && git checkout develop; done
+ git checkout develop
checkout_leapdeps_release:
pkg/scripts/checkout_leap_versions.sh
diff --git a/README.rst b/README.rst
index 5b611b95..c2738041 100644
--- a/README.rst
+++ b/README.rst
@@ -3,9 +3,8 @@ Bitmask
*your internet encryption toolkit*
-.. image:: https://pypip.in/v/leap.bitmask/badge.png
- :target: https://crate.io/packages/leap.bitmask
-.. image:: https://pypip.in/d/leap.bitmask/badge.png
+.. image:: https://badge.fury.io/py/leap.bitmask.svg
+ :target: http://badge.fury.io/py/leap.bitmask
**Bitmask** is the multiplatform desktop client for the services offered by
`the LEAP Platform`_.
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 00000000..d5a7b57e
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,32 @@
+FROM ubuntu:trusty
+
+MAINTAINER Ivan Alejandro <ivanalejandro0@gmail.com>
+
+RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+ g++ \
+ git \
+ libffi-dev \
+ libsqlite3-dev \
+ libssl-dev \
+ libzmq-dev \
+ openvpn \
+ pyside-tools \
+ python-dev \
+ python-openssl \
+ python-pip \
+ python-pyside \
+ python-setuptools \
+ python-virtualenv \
+ make realpath lxpolkit policykit-1 iptables && \
+ apt-get clean && rm -rf /var/lib/apt/lists/*
+
+
+RUN mkdir -p /bitmask
+WORKDIR /bitmask
+
+COPY leap_bootstrap.sh /bitmask/
+
+VOLUME ["/data/"]
+
+EXPOSE 1984 2013
+ENTRYPOINT ["/bitmask/leap_bootstrap.sh"]
diff --git a/docker/README.rst b/docker/README.rst
new file mode 100644
index 00000000..dcad0ac6
--- /dev/null
+++ b/docker/README.rst
@@ -0,0 +1,49 @@
+Bitmask and Docker
+==================
+
+Here we have several tools that leverages docker to ease Bitmask testing.
+
+``bitmask-docker.sh`` is a helper script to ``build`` and ``run`` the bitmask app,
+here is an example usage::
+
+ $ ./bitmask-docker build # build docker image
+ $ ./bitmask-docker init ro bitmask-nightly.json # initialize all the stuff needed
+ # ....
+ $ ./bitmask-docker.sh run
+
+
+``bitmask-nightly.json`` is the version specifier for each bitmask component that
+will be used to run bitmask.
+
+``Dockerfile`` is the file used to build the docker image that will run bitmask.
+
+``leap_bootstrap.sh`` is the script that takes care of cloning repos, installing
+python dependencies, running bitmask, etc.
+
+
+debian/
+-------
+
+``apt-bitmask.sh`` script that installs bitmask from the debian packages.
+
+``bitmask-on-docker.sh`` installs bitmask and runs it in a dummy X server,
+waits a little and takes a screenshot.
+
+``leap-experimental.key`` is needed by ``apt-bitmask.sh`` to ``apt-key add``
+and verify apt sources.
+
+``run-docker-for-bitmask.sh`` is a helper script that runs an ubuntu/debian
+container ready to run the ``apt-bitmask.sh`` command, it does (among other
+stuff) X11 forwarding to display Bitmask UI on the host linux.
+
+An example usage::
+
+ $ ./run-docker-for-bitmask.sh
+ non-network local connections being added to access control list
+ root@hostname:/# cd /host/
+ root@hostname:/host# ./apt-bitmask.sh unstable
+ # [... not so relevant output ...]
+ root@hostname:/host# apt-get install -y lxpolkit # install a small polkit agent
+ # [... not so relevant output ...]
+ root@hostname:/host# lxpolkit & # run the polkit agent in the background, ignore the "No session for pid 6034" error.
+ root@hostname:/host# bitmask -d # tadaa, you have bitmask running in a container!
diff --git a/docker/bitmask-docker.sh b/docker/bitmask-docker.sh
new file mode 100755
index 00000000..af91145b
--- /dev/null
+++ b/docker/bitmask-docker.sh
@@ -0,0 +1,116 @@
+#!/bin/bash
+
+run(){
+ # NOTE: you may need this line if you get an error using ip6tables
+ # (host needs ip6 kernel modules to use it in the container)
+ # sudo modprobe ip6_tables
+
+ # NOTE: to get X11 socket forwarding to work we need this
+ xhost local:root
+
+ CREDS_OPTS=''
+ if [[ -n $BITMASK_CREDENTIALS ]]; then
+ BITMASK_CREDENTIALS=`realpath $BITMASK_CREDENTIALS`
+ CREDS_OPTS="-e BITMASK_CREDENTIALS=/data/credentials.ini -v $BITMASK_CREDENTIALS:/data/credentials.ini"
+ fi
+
+ docker run --rm -it \
+ --net host \
+ --privileged \
+ -v /tmp/.X11-unix:/tmp/.X11-unix \
+ -e DISPLAY=unix$DISPLAY \
+ $CREDS_OPTS \
+ -v `pwd`/data/:/data/ -v `pwd`:/SHARED/ \
+ -v `pwd`/data/config:/root/.config/leap \
+ -p 1984:1984 -p 2013:2013 \
+ --name bitmask \
+ test/bitmask run $@
+
+ # Services' related ports
+ # eip: ["80", "53", "443", "1194"]
+ # mail: ["1984", "2013"]
+
+ # logs when no ip6_tables module is not loaded on host:
+ # root@bitmask-container:/bitmask# sudo ip6tables --new-chain bitmask
+ # modprobe: ERROR: ../libkmod/libkmod.c:556 kmod_search_moddep() could not open moddep file '/lib/modules/4.1.6-040106-generic/modules.dep.bin'
+ # ip6tables v1.4.21: can't initialize ip6tables table `filter': Table does not exist (do you need to insmod?)
+ # Perhaps ip6tables or your kernel needs to be upgraded.
+
+ # logs when ip6_tables module is loaded on host:
+ # root@bitmask-container:/bitmask# sudo ip6tables --new-chain bitmask
+ # root@bitmask-container:/bitmask# # success!
+}
+
+shell(){
+ xhost local:root
+
+ docker run --rm -it \
+ --net host \
+ --privileged \
+ -v /tmp/.X11-unix:/tmp/.X11-unix \
+ -e DISPLAY=unix$DISPLAY \
+ -v `pwd`/data/:/data/ -v `pwd`:/SHARED/ \
+ -v `pwd`/data/config:/root/.config/leap \
+ -p 1984:1984 -p 2013:2013 \
+ --name bitmask \
+ --entrypoint=bash \
+ test/bitmask
+}
+
+init(){
+ JSON=`realpath $1`
+ docker run --rm -it \
+ -v `pwd`/data:/data \
+ -v $JSON:/shared/bitmask.json \
+ test/bitmask init ro /shared/bitmask.json
+}
+
+update(){
+ JSON=`realpath $1`
+ docker run --rm -it \
+ -v `pwd`/data:/data \
+ -v $JSON:/shared/bitmask.json \
+ test/bitmask update /shared/bitmask.json
+}
+
+build(){
+ docker build -t test/bitmask .
+}
+
+help() {
+ echo ">> Bitmask on docker"
+ echo "Run the bitmask app in a docker container."
+ echo
+ echo "Usage: $0 {init bitmask.json | update | run | help }"
+ echo
+ echo " init : Clone repositories, install dependencies, and get bitmask ready to be used."
+ echo " The bitmask.json file contains the version that will be used for each repo."
+ echo " build : Build the docker image for bitmask."
+ echo " shell : Run a shell inside a bitmask docker container (useful to debug)."
+ echo " update : Update the repositories and install new deps (if needed)."
+ echo " run : Run the client (any extra parameters will be sent to the app)."
+ echo " help : Show this help"
+ echo
+}
+
+
+case "$1" in
+ run)
+ run "$@"
+ ;;
+ init)
+ init $2
+ ;;
+ update)
+ update $2
+ ;;
+ build)
+ build
+ ;;
+ shell)
+ shell
+ ;;
+ *)
+ help
+ ;;
+esac
diff --git a/docker/bitmask-nightly.json b/docker/bitmask-nightly.json
new file mode 100644
index 00000000..5b1c3cf0
--- /dev/null
+++ b/docker/bitmask-nightly.json
@@ -0,0 +1,11 @@
+{
+ "version": "nightly",
+ "tuf_repo": "",
+ "bitmask_client": "develop",
+ "soledad": "develop",
+ "keymanager": "develop",
+ "leap_mail": "develop",
+ "leap_pycommon": "develop",
+ "bitmask_launcher": "develop",
+ "leap_assets": "master"
+}
diff --git a/docker/debian/apt-bitmask.sh b/docker/debian/apt-bitmask.sh
new file mode 100755
index 00000000..68430aff
--- /dev/null
+++ b/docker/debian/apt-bitmask.sh
@@ -0,0 +1,122 @@
+#!/bin/bash
+set -euo pipefail
+IFS=$'\n\t'
+
+distro(){
+ # for ubuntu/mint:
+ name=`lsb_release -a 2>&1 | grep Codename | cut -f2`
+
+ # for debian:
+ [[ -z $name ]] && name=`grep -oP "VERSION=.*\(\K\w+" /etc/os-release`
+
+ # for debian sid
+ [[ -z $name ]] && name=`grep -o sid /etc/debian_version`
+
+ declare -A distros
+ distros=(
+ ['nadia']='quantal'
+ ['olivia']='raring'
+ ['petra']='saucy'
+ ['qiana']='trusty'
+ ['rebecca']='trusty'
+ ['rafaela']='trusty'
+ )
+
+ # if name is in the above list -> replace
+ [ ${distros[$name]+abc} ] && name=${distros[$name]}
+
+ echo $name | tr "[A-Z]" "[a-z]"
+}
+
+is_supported(){
+ distros=(
+ 'wheezy' # Debian 7 - stable
+ 'jessie' # Debian 8 - testing
+ 'sid' # Debian unstable
+ 'quantal' # Ubuntu 12.10
+ 'raring' # Ubuntu 13.04
+ 'saucy' # Ubuntu 13.10
+ 'trusty' # Ubuntu 14.04
+ 'utopic' # Ubuntu 14.10
+ 'vivid' # Ubuntu 15.04
+ )
+
+ my_distro=`distro`
+
+ for p in "${distros[@]}"; do
+ if [[ $my_distro = ${p}* ]]; then
+ echo true
+ return
+ fi
+ done
+ echo false
+}
+
+if [[ `is_supported` == "false" ]]; then
+ echo "ERROR: Sorry, your distro (`distro`) is currently not supported."
+ exit 1
+fi;
+
+help() {
+ echo ">> Bitmask .deb automatic installer helper"
+ echo "This script does all the needed stuff in order to get bitmask stable or unstable into your machine."
+ echo
+ echo "Usage: $0 ( stable | unstable | help )"
+ echo
+ echo " stable : Install the stable bitmask package."
+ echo " unstable : Install the unstable bitmask package."
+ echo " help : Show this help"
+ echo
+ echo "NOTE: you need to run this with root privileges."
+ echo
+}
+
+case ${1:-} in
+ stable)
+ REPO='debian'
+ ;;
+ unstable)
+ REPO='experimental'
+ ;;
+ *)
+ help
+ exit 1
+ ;;
+esac
+
+if [[ $EUID -ne 0 ]]; then
+ echo "This script must be run as root" 1>&2
+ exit 1
+fi
+
+# -------------------------------
+# instructions from http://deb.leap.se/experimental/
+# run this with admin privileges
+
+DISTRO=`distro`
+
+if [[ $REPO == 'debian' ]]; then
+ # stable
+ # wget -O- https://dl.bitmask.net/apt.key | apt-key add -
+
+ # HACK: do this twice since the first one fails due to gpg not having a configuration
+ gpg --recv-key 0x1E34A1828E207901 &> /dev/null || true
+ gpg --recv-key 0x1E34A1828E207901
+
+ gpg --armor --export 0x1E34A1828E207901 | apt-key add -
+else # $REPO == 'experimental'
+ if [[ ! -f "leap-experimental.key" ]]; then
+ echo "ERROR: you need to copy the leap-experimental.key file into this directory."
+ exit 1
+ fi
+
+ # sha256sum leap-experimental.key
+ echo "ed3f4f3e3e0835a044457451755ae743741d7bafa55bcd31cc464a54e8c5e7f9 leap-experimental.key" | sha256sum -c -
+ apt-key add leap-experimental.key
+fi
+
+echo "deb http://deb.leap.se/$REPO $DISTRO main" > /etc/apt/sources.list.d/bitmask.list
+echo "deb-src http://deb.leap.se/$REPO $DISTRO main" >> /etc/apt/sources.list.d/bitmask.list
+
+apt-get update
+apt-get install -y bitmask
diff --git a/docker/debian/bitmask-on-docker.sh b/docker/debian/bitmask-on-docker.sh
new file mode 100755
index 00000000..c3e42b22
--- /dev/null
+++ b/docker/debian/bitmask-on-docker.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+# Helper script to install, run and do a screenshot of bitmask
+
+# You can use this as follows:
+# $ docker run -t -i --rm -v `pwd`:/host/ ubuntu:14.04 /bin/bash
+# $ cd /host/
+# $ ./bitmask-on-docker.sh stable
+
+[[ -z $1 ]] && exit 1
+
+./apt-bitmask.sh $1 # this does an `apt-get update`
+apt-get -y install xinit xvfb imagemagick lxpolkit
+
+startx -- `which Xvfb` :1 -screen 0 1024x768x24 &
+sleep 1
+
+DISPLAY=:1 lxpolkit &
+sleep 0.5 # bitmask needs polkit to work
+
+DISPLAY=:1 bitmask &
+sleep 2 # wait for bitmask to start
+
+DISPLAY=:1 import -window root bitmask.png
diff --git a/docker/debian/leap-experimental.key b/docker/debian/leap-experimental.key
new file mode 100644
index 00000000..a07ec44c
--- /dev/null
+++ b/docker/debian/leap-experimental.key
@@ -0,0 +1,52 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.12 (GNU/Linux)
+
+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
+=10ZN
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/docker/debian/run-docker-for-bitmask.sh b/docker/debian/run-docker-for-bitmask.sh
new file mode 100755
index 00000000..9ffb400b
--- /dev/null
+++ b/docker/debian/run-docker-for-bitmask.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+# NOTE: to get X11 socket forwarding to work we need this
+xhost local:root
+
+docker run --rm -it \
+ --net host \
+ --privileged \
+ -v /tmp/.X11-unix:/tmp/.X11-unix \
+ -e DISPLAY=unix$DISPLAY \
+ -v `pwd`:/host/ \
+ -p 1984:1984 -p 2013:2013 \
+ ubuntu:vivid bash
+
+# NOTE: what to do next?
+# Install bitmask package:
+# $ apt-bitmask.sh stable
+# Install polkit agent (bitmask needs it):
+# $ apt-get install lxpolkit
+# Run polkit in background:
+# $ lxpolkit & # this will show you a message like: 'No session for pid 5801', ignore it
+# Run bitmask:
+# $ bitmask -d
diff --git a/docker/leap_bootstrap.sh b/docker/leap_bootstrap.sh
new file mode 100755
index 00000000..4f553ee7
--- /dev/null
+++ b/docker/leap_bootstrap.sh
@@ -0,0 +1,320 @@
+#!/bin/bash
+######################################################################
+# repo-versions.sh
+# Copyright (C) 2014, 2015 LEAP
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+######################################################################
+set -e # Exit immediately if a command exits with a non-zero status.
+REPOSITORIES="bitmask_client leap_pycommon soledad keymanager leap_mail bitmask_launcher leap_assets"
+PACKAGES="leap_pycommon keymanager soledad/common soledad/client leap_mail bitmask_client"
+
+_is_docker() {
+ grep -q docker /proc/1/cgroup
+}
+
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+_is_docker && BASE_PATH="/data/" || BASE_PATH=$SCRIPT_DIR
+REPOS_ROOT="$BASE_PATH/repositories" # Root path for all the needed repositories
+VENV_DIR="$BASE_PATH/bitmask.venv" # Root path for all the needed repositories
+
+mkdir -p $REPOS_ROOT
+
+PS4=">> " # for debugging
+
+# Escape code
+esc=`echo -en "\033"`
+
+# Set colors
+cc_green="${esc}[0;32m"
+cc_yellow="${esc}[0;33m"
+cc_blue="${esc}[0;34m"
+cc_red="${esc}[0;31m"
+cc_normal=`echo -en "${esc}[m\017"`
+
+apt_install_dependencies() {
+ status="installing system dependencies"
+ echo "${cc_green}Status: $status...${cc_normal}"
+ set -x
+ sudo apt-get install -y git python-dev python-setuptools python-virtualenv python-pip libssl-dev python-openssl libsqlite3-dev g++ openvpn pyside-tools python-pyside libffi-dev libzmq-dev
+ set +x
+}
+
+helpers() {
+ if [[ "$1" == "cleanup" ]]; then
+ status="removing helper files"
+ echo "${cc_green}Status: $status...${cc_normal}"
+ set -x
+ sudo rm -f /usr/sbin/bitmask-root
+ sudo rm -f /usr/share/polkit-1/actions/se.leap.bitmask.policy
+ set +x
+ else
+ status="installing helper files"
+ echo "${cc_green}Status: $status...${cc_normal}"
+ set -x
+ BASE=$REPOS_ROOT/bitmask_client/pkg/linux
+ sudo mkdir -p /usr/share/polkit-1/actions/
+ sudo cp $BASE/bitmask-root /usr/sbin/
+ sudo cp $BASE/polkit/se.leap.bitmask.policy /usr/share/polkit-1/actions/
+ set +x
+ fi
+}
+
+clone_repos() {
+ local status="clone repositories"
+ echo "${cc_green}Status: $status...${cc_normal}"
+ set -x # show commands
+
+ if [[ "$1" == "rw" ]]; then
+ # read-write remotes:
+ src="ssh://gitolite@leap.se"
+ else
+ # read-only remotes:
+ src="https://leap.se/git"
+ fi
+ cd $REPOS_ROOT
+
+ for repo in $REPOSITORIES; do
+ [ ! -d $repo ] && git clone $src/$repo
+ done
+
+ cd -
+
+ set +x
+ echo "${cc_green}Status: $status done!${cc_normal}"
+}
+
+checkout_repos(){
+ local status="checkout repositories"
+ echo "${cc_green}Status: $status...${cc_normal}"
+ set -x # show commands
+
+ for repo in $REPOSITORIES; do
+ version=$(cat $1 | python -c "import json,sys;obj=json.load(sys.stdin);print obj['$repo'];")
+ cd $REPOS_ROOT/$repo
+ git fetch origin && git fetch --tags origin
+
+ if [[ -n `git tag -l | grep $version` ]]; then
+ # if is a tag
+ git checkout -f $version
+ else
+ # if is a branch
+ git reset --hard origin/$version
+ fi
+ done
+
+ set +x
+ echo "${cc_green}Status: $status done!${cc_normal}"
+}
+
+create_venv() {
+ local status="creating virtualenv"
+ echo "${cc_green}Status: $status...${cc_normal}"
+ set -x # show commands
+
+ virtualenv $VENV_DIR && source $VENV_DIR/bin/activate
+ pip install --upgrade pip # get the latest pip
+
+ set +x
+ echo "${cc_green}Status: $status done.${cc_normal}"
+}
+
+setup_develop() {
+ local status="installing packages"
+ echo "${cc_green}Status: $status...${cc_normal}"
+ set -x # show commands
+ cd $REPOS_ROOT
+ source $VENV_DIR/bin/activate
+
+ # do a setup develop in every package
+ for package in $PACKAGES; do
+ cd $REPOS_ROOT/$package
+ python setup.py develop --always-unzip
+ done
+
+ set +x
+ echo "${cc_green}Status: $status done.${cc_normal}"
+}
+
+install_dependencies() {
+ local status="installing dependencies"
+ echo "${cc_green}Status: $status...${cc_normal}"
+ set -x # show commands
+ cd $REPOS_ROOT
+ source $VENV_DIR/bin/activate
+
+ # install defined 3rd party dependencies for every package
+ for package in $PACKAGES; do
+ cd $REPOS_ROOT/$package
+ pkg/pip_install_requirements.sh --use-leap-wheels
+ done
+
+ # symlink system's PySide inside the venv
+ $REPOS_ROOT/bitmask_client/pkg/postmkvenv.sh
+
+ # hack to solve gnupg version problem
+ pip uninstall -y gnupg && pip install gnupg
+
+ set +x
+ echo "${cc_green}Status: $status done.${cc_normal}"
+}
+
+docker_stuff() {
+ local status="doing stuff needed to run bitmask on a docker container"
+ echo "${cc_green}Status: $status...${cc_normal}"
+ set -x # show commands
+
+ helpers
+ lxpolkit &
+ sleep 0.5
+
+ # this is needed for pkexec
+ mkdir -p /var/run/dbus
+ dbus-daemon --system | true
+
+ set +x
+ echo "${cc_green}Status: $status done.${cc_normal}"
+}
+
+run() {
+ echo "${cc_green}Status: running client...${cc_normal}"
+ set -x
+
+ shift # remove 'run' from arg list
+ passthrough_args=$@
+
+ _is_docker && docker_stuff
+
+ source $VENV_DIR/bin/activate
+ python $REPOS_ROOT/bitmask_client/src/leap/bitmask/app.py -d $passthrough_args
+
+ set +x
+}
+
+initialize() {
+ shift # remove 'init'
+ echo $@
+ if [[ "$1" == "ro" ]]; then
+ # echo "RO"
+ shift # remove 'ro'
+ clone_repos "ro"
+ else
+ # echo "RW"
+ clone_repos
+ fi
+
+ if [[ -z $1 ]]; then
+ echo "You need to specify a bitmask.json parameter."
+ echo "for example:"
+ cat << EOF
+{
+ "bitmask_client": "0.7.0",
+ "soledad": "0.6.3",
+ "leap_pycommon": "0.3.9",
+ "keymanager": "0.3.8",
+ "leap_mail": "0.3.10",
+ "bitmask_launcher": "0.3.3",
+ "leap_assets": "master"
+}
+EOF
+ exit 1
+ fi
+
+ JSON=`realpath $1`
+
+ checkout_repos $JSON
+ create_venv
+ install_dependencies
+ setup_develop
+
+ cd $REPOS_ROOT/bitmask_client/
+ make
+ cd -
+}
+update() {
+ local status="updating repositories"
+ echo "${cc_green}Status: $status...${cc_normal}"
+ set -x # show commands
+
+ if [[ -z $1 ]]; then
+ echo "You need to specify a bitmask.json parameter."
+ echo "for example:"
+ cat << EOF
+{
+ "bitmask_client": "0.7.0",
+ "soledad": "0.6.3",
+ "leap_pycommon": "0.3.9",
+ "keymanager": "0.3.8",
+ "leap_mail": "0.3.10",
+ "bitmask_launcher": "0.3.3",
+ "leap_assets": "master"
+}
+EOF
+ exit 1
+ fi
+
+ JSON=`realpath $1`
+
+ checkout_repos $JSON
+ install_dependencies
+ setup_develop
+
+ set +x
+ echo "${cc_green}Status: $status done!${cc_normal}"
+}
+
+
+help() {
+ echo ">> LEAP bootstrap - help"
+ echo "Bootstraps the environment to start developing the bitmask client"
+ echo "with all the needed repositories and dependencies."
+ echo
+ echo "Usage: $0 {init [ro] bitmask.json | update bitmask.json | run | help | deps | helpers}"
+ echo
+ echo " init : Initialize repositories, create virtualenv and \`python setup.py develop\` all."
+ echo " You can use \`init ro\` in order to use the https remotes if you don't have rw access."
+ echo " The bitmask.json file contains the version that will be used for each repo."
+ echo " update : Update the repositories and install new deps (if needed)."
+ echo " The bitmask.json file contains the version that will be used for each repo."
+ echo " run : Runs the client (any extra parameters will be sent to the app)."
+ echo " help : Show this help"
+ echo " -- system helpers --"
+ echo " deps : Install the system dependencies needed for bitmask dev (Debian based Linux ONLY)."
+ echo " helpers : Install the helper files needed to use bitmask (Linux only)."
+ echo " You can use \`helpers cleanup\` to remove those files."
+ echo
+}
+
+
+case "$1" in
+ init)
+ initialize "$@"
+ ;;
+ update)
+ update $2
+ ;;
+ helpers)
+ helpers $2
+ ;;
+ deps)
+ apt_install_dependencies
+ ;;
+ run)
+ run "$@"
+ ;;
+ *)
+ help
+ ;;
+esac
diff --git a/docs/man/bitmask-root.1.rst b/docs/man/bitmask-root.1.rst
index 7faf081b..4a3859ba 100644
--- a/docs/man/bitmask-root.1.rst
+++ b/docs/man/bitmask-root.1.rst
@@ -35,8 +35,8 @@ openvpn
**start** [ARGS] Starts openvpn. All args are passed to openvpn, and
filtered against a list of allowed args. If the next
- argument is `restart`, the firewall will not be teared
- down in the case of errors lauching openvpn.
+ argument is `restart`, the firewall will not be torn
+ down in the case of errors launching openvpn.
**stop** Stops openvpn.
diff --git a/pkg/leap_versions.txt b/pkg/leap_versions.txt
index 0351c758..ff0dd91c 100644
--- a/pkg/leap_versions.txt
+++ b/pkg/leap_versions.txt
@@ -1,4 +1,4 @@
-soledad 0.7.1
-keymanager 0.4.1
-leap_common 0.4.0
-leap_mail 0.4.0rc1
+soledad 0.7.2
+keymanager 0.4.2
+leap_common 0.4.2
+leap_mail 0.4.0rc2
diff --git a/pkg/requirements.pip b/pkg/requirements.pip
index 4467c32c..b86346d0 100644
--- a/pkg/requirements.pip
+++ b/pkg/requirements.pip
@@ -27,5 +27,4 @@ txzmq
# Remove this when u1db fixes its dependency on oauth
oauth
-#taskthread
-logbook
+logbook>=0.7.0
diff --git a/setup.cfg b/setup.cfg
index e91c4adb..1a05d2c3 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -9,8 +9,8 @@ repository = https://pypi.python.org/pypi
[pep8]
ignore = E731
-exclude = *_rc.py,ui_*,_version.py
+exclude = *_rc.py,ui_*,_version.py,docker,build,docs,pkg,versioneer.py,_binaries.py,pinned_*
[flake8]
ignore = E731
-exclude = *_rc.py,ui_*,_version.py
+exclude = *_rc.py,ui_*,_version.py,docker,build,docs,pkg,versioneer.py,_binaries.py
diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index a2e2aa1a..c9c02b59 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -133,6 +133,7 @@ def log_lsb_release_info(logger):
for line in distro_info:
logger.info(line)
+
def fix_qtplugins_path():
# This is a small workaround for a bug in macholib, there is a slight typo
# in the path for the qt plugins that is added to the dynamic loader path
diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py
index 30b7c5d1..ae300b32 100644
--- a/src/leap/bitmask/backend/backend_proxy.py
+++ b/src/leap/bitmask/backend/backend_proxy.py
@@ -27,8 +27,6 @@ import zmq
from zmq.eventloop import ioloop
from zmq.eventloop import zmqstream
-from taskthread import TimerTask
-
from leap.bitmask.backend.api import API, STOP_REQUEST, PING_REQUEST
from leap.bitmask.backend.settings import Settings
from leap.bitmask.backend.utils import generate_zmq_certificates_if_needed
@@ -141,7 +139,8 @@ class BackendProxy(object):
self._do_work = threading.Event()
self._work_lock = threading.Lock()
self._connection = ZmqREQConnection(self.SERVER, self._set_online)
- self._heartbeat = TimerTask(self._ping, delay=self.PING_INTERVAL)
+ self._heartbeat = threading.Timer(self.PING_INTERVAL,
+ self._heartbeat_loop)
self._ping_event = threading.Event()
self.online = False
self.settings = Settings()
@@ -197,17 +196,25 @@ class BackendProxy(object):
"""
with self._work_lock: # avoid sending after connection was closed
self._do_work.clear()
- self._heartbeat.stop()
+ self._heartbeat.cancel()
self._connection.stop()
logger.debug("BackendProxy worker stopped.")
- def _ping(self):
+ def _heartbeat_loop(self):
"""
- Heartbeat helper.
- Sends a PING request just to know that the server is alive.
+ Sends a PING request every PING_INTERVAL just to know that the server
+ is alive.
"""
self._send_request(PING_REQUEST)
+ # lets acquire the lock to prevent heartbeat timer to get cancel while
+ # we set a new one
+ with self._work_lock:
+ if self._do_work.is_set():
+ self._heartbeat = threading.Timer(self.PING_INTERVAL,
+ self._heartbeat_loop)
+ self._heartbeat.start()
+
def _api_call(self, *args, **kwargs):
"""
Call the `api_method` method in backend (through zmq).
diff --git a/src/leap/bitmask/crypto/certs.py b/src/leap/bitmask/crypto/certs.py
index 4b669376..017af144 100644
--- a/src/leap/bitmask/crypto/certs.py
+++ b/src/leap/bitmask/crypto/certs.py
@@ -30,7 +30,7 @@ from leap.common import certs as leap_certs
logger = get_logger()
-def download_client_cert(provider_config, path, session):
+def download_client_cert(provider_config, path, session, kind="vpn"):
"""
Downloads the client certificate for each service.
@@ -41,32 +41,45 @@ def download_client_cert(provider_config, path, session):
:param session: a fetcher.session instance. For the moment we only
support requests.sessions
:type session: requests.sessions.Session
+ :param kind: the kind of certificate being requested. Valid values are
+ "vpn" or "smtp".
+ :type kind: string
"""
- # TODO we should implement the @with_srp_auth decorator
- # again.
srp_auth = SRPAuth(provider_config)
session_id = srp_auth.get_session_id()
token = srp_auth.get_token()
cookies = None
if session_id is not None:
cookies = {"_session_id": session_id}
- cert_uri = "%s/%s/cert" % (
+
+ if kind == "vpn":
+ cert_uri_template = "%s/%s/cert"
+ method = 'get'
+ params = {}
+ elif kind == 'smtp':
+ cert_uri_template = "%s/%s/smtp_cert"
+ method = 'post'
+ params = {'address': srp_auth.get_username()}
+ else:
+ raise ValueError("Incorrect value passed to kind parameter")
+
+ cert_uri = cert_uri_template % (
provider_config.get_api_uri(),
provider_config.get_api_version())
- logger.debug('getting cert from uri: %s' % cert_uri)
+
+ logger.debug('getting %s cert from uri: %s' % (kind, cert_uri))
headers = {}
# API v2 will only support token auth, but in v1 we can send both
if token is not None:
- headers["Authorization"] = 'Token token="{0}"'.format(token)
+ headers["Authorization"] = 'Token token={0}'.format(token)
- res = session.get(cert_uri,
- verify=provider_config
- .get_ca_cert_path(),
- cookies=cookies,
- timeout=REQUEST_TIMEOUT,
- headers=headers)
+ call = getattr(session, method)
+ res = call(cert_uri, verify=provider_config.get_ca_cert_path(),
+ cookies=cookies, params=params,
+ timeout=REQUEST_TIMEOUT,
+ headers=headers, data=params)
res.raise_for_status()
client_cert = res.content
@@ -74,7 +87,6 @@ def download_client_cert(provider_config, path, session):
# XXX raise more specific exception.
raise Exception("The downloaded certificate is not a "
"valid PEM file")
-
mkdir_p(os.path.dirname(path))
try:
diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py
index 452bfa66..97a4e958 100644
--- a/src/leap/bitmask/crypto/srpauth.py
+++ b/src/leap/bitmask/crypto/srpauth.py
@@ -552,12 +552,19 @@ class SRPAuthImpl(object):
self._provider_config.
get_api_version(),
"logout")
+ cookies = {self.SESSION_ID_KEY: self.get_session_id()}
+ headers = {
+ self.AUTHORIZATION_KEY:
+ "Token token={0}".format(self.get_token())
+ }
try:
- self._session.delete(logout_url,
- data=self.get_session_id(),
- verify=self._provider_config.
- get_ca_cert_path(),
- timeout=REQUEST_TIMEOUT)
+ res = self._session.delete(
+ logout_url,
+ cookies=cookies,
+ headers=headers,
+ verify=self._provider_config.
+ get_ca_cert_path(),
+ timeout=REQUEST_TIMEOUT)
except Exception as e:
logger.warning("Something went wrong with the logout: %r" %
(e,))
@@ -568,7 +575,10 @@ class SRPAuthImpl(object):
self.set_token(None)
# Also reset the session
self._session = self._fetcher.session()
- logger.debug("Successfully logged out.")
+ if res.status_code == 204:
+ logger.debug("Successfully logged out.")
+ else:
+ logger.debug("Logout status code: %s" % res.status_code)
def set_session_id(self, session_id):
with self._session_id_lock:
diff --git a/src/leap/bitmask/gui/account.py b/src/leap/bitmask/gui/account.py
index c941c3fa..81f96389 100644
--- a/src/leap/bitmask/gui/account.py
+++ b/src/leap/bitmask/gui/account.py
@@ -43,7 +43,7 @@ class Account():
return self._settings.get_enabled_services(self.domain)
def is_email_enabled(self):
- MX_SERVICE in self.services()
+ return MX_SERVICE in self.services()
def is_eip_enabled(self):
- EIP_SERVICE in self.services()
+ return EIP_SERVICE in self.services()
diff --git a/src/leap/bitmask/gui/app.py b/src/leap/bitmask/gui/app.py
index 02357b2b..97fd0549 100644
--- a/src/leap/bitmask/gui/app.py
+++ b/src/leap/bitmask/gui/app.py
@@ -43,6 +43,8 @@ class App(QtGui.QWidget):
self.signaler = LeapSignaler()
self.signaler.start()
+ self.soledad_started = False
+
# periodically check if the backend is alive
self._backend_checker = QtCore.QTimer(self)
self._backend_checker.timeout.connect(self._check_backend_status)
diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py
index 8334c2ee..64a408c4 100644
--- a/src/leap/bitmask/gui/eip_status.py
+++ b/src/leap/bitmask/gui/eip_status.py
@@ -96,7 +96,8 @@ class EIPStatusWidget(QtGui.QWidget):
# Action for the systray
self._eip_disabled_action = QtGui.QAction(
- u"{0} is {1}".format(self._service_name, self.tr("disabled")), self)
+ u"{0} is {1}".format(
+ self._service_name, self.tr("disabled")), self)
def connect_backend_signals(self):
"""
diff --git a/src/leap/bitmask/gui/login.py b/src/leap/bitmask/gui/login.py
index 756dd63c..4c2bd9c5 100644
--- a/src/leap/bitmask/gui/login.py
+++ b/src/leap/bitmask/gui/login.py
@@ -19,10 +19,12 @@ Login widget implementation
The login sequence is the following:
- _do_login
- - backend.provider_setup (check_name_resolution, check_https, download_provider_info)
+ - backend.provider_setup (
+ check_name_resolution, check_https, download_provider_info)
- on error: _provider_setup_intermediate
- on success: _load_provider_config
- - backend.provider_bootstrap (download_ca_cert, check_ca_fingerprint, check_api_certificate)
+ - backend.provider_bootstrap (
+ download_ca_cert, check_ca_fingerprint, check_api_certificate)
- on error: _provider_setup_intermediate
- on success: _provider_config_loaded
- backend.user_login
diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py
index 1a38c8cf..eebae49b 100644
--- a/src/leap/bitmask/gui/mail_status.py
+++ b/src/leap/bitmask/gui/mail_status.py
@@ -53,6 +53,8 @@ class MailStatusWidget(QtGui.QWidget):
self._disabled = True
self._started = False
+ self._unread_mails = 0
+
self.ui = Ui_MailStatusWidget()
self.ui.setupUi(self)
@@ -92,6 +94,8 @@ class MailStatusWidget(QtGui.QWidget):
callback=self._mail_handle_soledad_events)
register(event=catalog.SOLEDAD_INVALID_AUTH_TOKEN,
callback=self.set_soledad_invalid_auth_token)
+ register(event=catalog.SOLEDAD_DONE_DATA_SYNC,
+ callback=self._mail_handle_soledad_events)
register(event=catalog.MAIL_UNREAD_MESSAGES,
callback=self._mail_handle_imap_events)
@@ -277,6 +281,14 @@ class MailStatusWidget(QtGui.QWidget):
ext_status = self.tr("Sync: upload complete.")
ready = 2
+ elif event == catalog.SOLEDAD_DONE_DATA_SYNC:
+ if self._unread_mails > 0:
+ self._show_unread_mails()
+ return
+ else:
+ ext_status = self.tr("Sync: completed.")
+
+ ready = 2
else:
leap_assert(False,
"Don't know how to handle this state: %s"
@@ -395,21 +407,33 @@ class MailStatusWidget(QtGui.QWidget):
# We could make this configurable to include all unread mail
# or all unread mail in subscribed folders.
if self._started:
- count = content
- if count != "0":
- status = self.tr("{0} Unread Emails "
- "in your Inbox").format(count)
- if count == "1":
- status = self.tr("1 Unread Email in your Inbox")
-
- self._set_mail_status(status, ready=2)
- else:
- self._set_mail_status("", ready=2)
+ try:
+ self._unread_mails = int(content)
+ except:
+ self._unread_mails = 0
+
+ self._show_unread_mails()
elif event == catalog.IMAP_SERVICE_STARTED:
self._imap_started = True
if ext_status is not None:
self._set_mail_status(ext_status, ready=1)
+ def _show_unread_mails(self):
+ """
+ Show the user the amount of unread emails.
+ """
+ count = self._unread_mails
+
+ if count > 0:
+ status = self.tr("{0} Unread Emails "
+ "in your Inbox").format(count)
+ if count == 1:
+ status = self.tr("1 Unread Email in your Inbox")
+
+ self._set_mail_status(status, ready=2)
+ else:
+ self._set_mail_status("", ready=2)
+
def about_to_start(self):
"""
Display the correct UI for the point where mail components
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 312048ba..387c6283 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -17,8 +17,11 @@
"""
Main window for Bitmask.
"""
+import os
import time
+import ConfigParser
+
from datetime import datetime
import psutil
@@ -198,8 +201,6 @@ class MainWindow(QtGui.QMainWindow, SignalTracker):
self._login_widget.login_offline_finished.connect(
self._maybe_run_soledad_setup_checks)
- self._soledad_started = False
-
# This is created once we have a valid provider config
self._logged_in_offline = False
@@ -541,7 +542,7 @@ class MainWindow(QtGui.QMainWindow, SignalTracker):
# XXX: handle differently not logged in user?
akm = AdvancedKeyManagement(self, mx_provided, logged_user,
- self._backend, self._soledad_started)
+ self._backend, self.app.soledad_started)
akm.show()
def _show_preferences(self):
@@ -781,6 +782,10 @@ class MainWindow(QtGui.QMainWindow, SignalTracker):
if self._wizard:
self._load_from_wizard()
else:
+ if self._load_credentials_from_env():
+ self._login()
+ return
+
domain = self._settings.get_provider()
if domain is not None:
self._providers.select_provider_by_name(domain)
@@ -796,6 +801,35 @@ class MainWindow(QtGui.QMainWindow, SignalTracker):
if self._login_widget.load_user_from_keyring(saved_user):
self._login()
+ def _load_credentials_from_env(self):
+ """
+ Load username and password into the login widget from a file specified
+ in an environment variable. This is useful for test purposes.
+
+ :return: True if credentials were loaded, False otherwise
+ :rtype: bool
+ """
+ credentials = os.environ.get("BITMASK_CREDENTIALS")
+
+ if credentials is None:
+ return False
+
+ try:
+ config = ConfigParser.ConfigParser()
+ config.read(credentials)
+ username, domain = config.get('Credentials', 'username').split('@')
+ password = config.get('Credentials', 'password')
+ except Exception, e:
+ print "Error reading credentials file: {0}".format(e)
+ return False
+
+ self._providers.select_provider_by_name(domain)
+ self._login_widget.set_provider(domain)
+ self._login_widget.set_user(username)
+ self._login_widget.set_password(password)
+
+ return True
+
def _show_hide_unsupported_services(self):
"""
Given a set of configured providers, it creates a set of
@@ -1202,7 +1236,7 @@ class MainWindow(QtGui.QMainWindow, SignalTracker):
self._backend.soledad_cancel_bootstrap()
self._backend.soledad_close()
- self._soledad_started = False
+ self.app.soledad_started = True
def _on_user_logged_in(self):
"""
@@ -1378,7 +1412,7 @@ class MainWindow(QtGui.QMainWindow, SignalTracker):
"""
logger.debug("Done bootstrapping Soledad")
- self._soledad_started = True
+ self.app.soledad_started = True
self.soledad_ready.emit()
###################################################################
@@ -1604,14 +1638,12 @@ class MainWindow(QtGui.QMainWindow, SignalTracker):
# window handling methods
#
- def _on_raise_window_event(self, event, content):
+ def _on_raise_window_event(self, event):
"""
Callback for the raise window event
:param event: The event that triggered the callback.
:type event: str
- :param content: The content of the event.
- :type content: list
"""
if IS_WIN:
locks.raise_window_ack()
diff --git a/src/leap/bitmask/gui/passwordwindow.py b/src/leap/bitmask/gui/passwordwindow.py
index 94cf25da..dedfcb10 100644
--- a/src/leap/bitmask/gui/passwordwindow.py
+++ b/src/leap/bitmask/gui/passwordwindow.py
@@ -71,9 +71,10 @@ class PasswordWindow(QtGui.QDialog, Flashable):
self.ui.cancel_button.setEnabled(True)
self.flash_error(self.tr("Please log in to change your password."))
- if self.is_soledad_needed() and not self._soledad_ready:
+ if self.is_soledad_needed() and not self.app.soledad_started:
self._enable_password_widgets(False)
self.ui.cancel_button.setEnabled(True)
+
self.flash_message(
self.tr("Please wait for data storage to be ready."))
@@ -146,7 +147,6 @@ class PasswordWindow(QtGui.QDialog, Flashable):
sig.soledad_password_change_error.connect(
self._soledad_change_password_problem)
- self._soledad_ready = False
sig.soledad_bootstrap_finished.connect(self._on_soledad_ready)
def _change_password(self):
@@ -203,8 +203,14 @@ class PasswordWindow(QtGui.QDialog, Flashable):
new_password = self.ui.new_password_lineedit.text()
logger.debug("SRP password changed successfully.")
+ # FIXME ---- both changes need to be made atomically!
+ # if there is some problem changing password in soledad (for instance,
+ # it checks for length), any exception raised will be lost and we will
+ # have an inconsistent state between soledad and srp passwords.
+ # We need to implement rollaback.
+
if self.is_soledad_needed():
- self._backend.soledad_change_password(new_password=new_password)
+ self.app.backend.soledad_change_password(new_password=new_password)
else:
self._change_password_success()
@@ -263,4 +269,3 @@ class PasswordWindow(QtGui.QDialog, Flashable):
Signaler.soledad_bootstrap_finished
"""
self._enable_password_widgets(True)
- self._soledad_ready = True
diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py
index baa71252..44c4641c 100644
--- a/src/leap/bitmask/gui/preferenceswindow.py
+++ b/src/leap/bitmask/gui/preferenceswindow.py
@@ -70,7 +70,7 @@ class PreferencesWindow(QtGui.QDialog):
# only allow a single preferences window at a time.
if PreferencesWindow._current_window is not None:
- PreferencesWindow._current_window.close_window()
+ PreferencesWindow._current_window.close()
PreferencesWindow._current_window = self
def _add_icons(self):
diff --git a/src/leap/bitmask/logs/utils.py b/src/leap/bitmask/logs/utils.py
index 683fb542..f709da8b 100644
--- a/src/leap/bitmask/logs/utils.py
+++ b/src/leap/bitmask/logs/utils.py
@@ -112,7 +112,7 @@ def replace_stdout_stderr_with_logging(logger=None):
log.startLogging(sys.stdout)
-class QtLogHandler(logbook.Handler, logbook.StringFormatterHandlerMixin):
+class QtLogHandler(logbook.Handler, logbook.StringFormatterHandlerMixin):
"""
Custom log handler which emits a log record with the message properly
formatted using a Qt Signal.
@@ -186,6 +186,7 @@ class QtLogHandler(logbook.Handler, logbook.StringFormatterHandlerMixin):
class _LogController(object):
+
def __init__(self):
self._qt_handler = QtLogHandler(format_string=LOG_FORMAT)
self._logbook_controller = None
diff --git a/src/leap/bitmask/services/mail/imapcontroller.py b/src/leap/bitmask/services/mail/imapcontroller.py
index e5313477..5053d897 100644
--- a/src/leap/bitmask/services/mail/imapcontroller.py
+++ b/src/leap/bitmask/services/mail/imapcontroller.py
@@ -27,6 +27,7 @@ class IMAPController(object):
"""
IMAP Controller.
"""
+
def __init__(self, soledad, keymanager):
"""
Initialize IMAP variables.
@@ -63,12 +64,11 @@ class IMAPController(object):
self._soledad,
userid=userid)
- def start_incoming_service(incoming_mail):
- d = incoming_mail.startService()
- d.addCallback(lambda started: incoming_mail)
- return d
-
- def assign_incoming_service(incoming_mail):
+ def start_and_assign_incoming_service(incoming_mail):
+ # this returns a deferred that will be called when the looping call
+ # is stopped, we could add any shutdown/cleanup callback to that
+ # deferred, but unused by the moment.
+ incoming_mail.startService()
self.incoming_mail_service = incoming_mail
return incoming_mail
@@ -78,8 +78,7 @@ class IMAPController(object):
self._soledad,
self.imap_factory,
userid)
- d.addCallback(start_incoming_service)
- d.addCallback(assign_incoming_service)
+ d.addCallback(start_and_assign_incoming_service)
d.addErrback(lambda f: logger.error(f.printTraceback()))
def stop_imap_service(self):
diff --git a/src/leap/bitmask/services/mail/smtpbootstrapper.py b/src/leap/bitmask/services/mail/smtpbootstrapper.py
index cd871803..a577509e 100644
--- a/src/leap/bitmask/services/mail/smtpbootstrapper.py
+++ b/src/leap/bitmask/services/mail/smtpbootstrapper.py
@@ -18,6 +18,9 @@
SMTP bootstrapping
"""
import os
+import warnings
+
+from requests.exceptions import HTTPError
from leap.bitmask.config.providerconfig import ProviderConfig
from leap.bitmask.crypto.certs import download_client_cert
@@ -87,7 +90,7 @@ class SMTPBootstrapper(AbstractBootstrapper):
logger.debug("Using hostname %s for SMTP" % (hostname,))
client_cert_path = self._smtp_config.get_client_cert_path(
- self._provider_config, about_to_download=True)
+ self._userid, self._provider_config, about_to_download=True)
if not is_file(client_cert_path):
# For re-download if something is wrong with the cert
@@ -99,9 +102,25 @@ class SMTPBootstrapper(AbstractBootstrapper):
check_and_fix_urw_only(client_cert_path)
return
- download_client_cert(self._provider_config,
- client_cert_path,
- self._session)
+ try:
+ download_client_cert(self._provider_config,
+ client_cert_path,
+ self._session, kind="smtp")
+ except HTTPError as exc:
+ if exc.message.startswith('403 Client Error'):
+ logger.debug(
+ 'Auth problem downloading smtp certificate... '
+ 'It might be a provider problem, will try '
+ 'fetching from vpn pool')
+ warnings.warn(
+ 'Compatibility hack for platform 0.7 not fully '
+ 'supporting smtp certificates. Will be deprecated in '
+ 'bitmask 0.10')
+ download_client_cert(self._provider_config,
+ client_cert_path,
+ self._session, kind="vpn")
+ else:
+ raise
def _start_smtp_service(self):
"""
@@ -117,7 +136,7 @@ class SMTPBootstrapper(AbstractBootstrapper):
host = hosts[hostname][self.IP_KEY].encode("utf-8")
port = hosts[hostname][self.PORT_KEY]
client_cert_path = self._smtp_config.get_client_cert_path(
- self._provider_config, about_to_download=True)
+ self._userid, self._provider_config, about_to_download=True)
from leap.mail.smtp import setup_smtp_gateway
diff --git a/src/leap/bitmask/services/mail/smtpconfig.py b/src/leap/bitmask/services/mail/smtpconfig.py
index 2d8de411..f78b3449 100644
--- a/src/leap/bitmask/services/mail/smtpconfig.py
+++ b/src/leap/bitmask/services/mail/smtpconfig.py
@@ -53,19 +53,24 @@ class SMTPConfig(ServiceConfig):
return self._safe_get_value("locations")
def get_client_cert_path(self,
+ userid,
providerconfig=None,
about_to_download=False):
"""
Returns the path to the certificate used by smtp
+ :param userid: the user id, in user@provider form
"""
+ leap_assert(userid, "Need an userid")
leap_assert(providerconfig, "We need a provider")
leap_assert_type(providerconfig, ProviderConfig)
+ username = userid.split("@")[0]
+
cert_path = os.path.join(get_path_prefix(),
"leap", "providers",
providerconfig.get_domain(),
- "keys", "client", "smtp.pem")
+ "keys", "client", "smtp_%s.pem" % username)
if not about_to_download:
leap_assert(os.path.exists(cert_path),
diff --git a/src/leap/bitmask/updater.py b/src/leap/bitmask/updater.py
index c35eff5f..7cb23a0a 100644
--- a/src/leap/bitmask/updater.py
+++ b/src/leap/bitmask/updater.py
@@ -50,6 +50,7 @@ DELAY_KEY = "updater_delay"
class Updater(threading.Thread):
+
def __init__(self):
"""
Initialize the list of mirrors, paths and other TUF dependencies from
@@ -162,7 +163,8 @@ class Updater(threading.Thread):
"""
Find the remote repo path deneding on the platform.
- :return: the path to add to the remote repo url for the specific platform.
+ :return: the path to add to the remote repo url for the specific
+ platform.
:rtype: str
:raises NotImplemented: When the system where bitmask is running is not
diff --git a/src/leap/bitmask/util/__init__.py b/src/leap/bitmask/util/__init__.py
index 9853803a..b788abd0 100644
--- a/src/leap/bitmask/util/__init__.py
+++ b/src/leap/bitmask/util/__init__.py
@@ -156,6 +156,7 @@ def flags_to_dict():
return values
+
def here(module=None):
if getattr(sys, 'frozen', False):
# we are running in a |PyInstaller| bundle
@@ -163,6 +164,6 @@ def here(module=None):
else:
dirname = os.path.dirname
if module:
- return dirname(module.__file__)
+ return dirname(module.__file__)
else:
return dirname(__file__)
diff --git a/src/leap/bitmask/util/pastebin.py b/src/leap/bitmask/util/pastebin.py
index a3bdba02..6d50ac9e 100644
--- a/src/leap/bitmask/util/pastebin.py
+++ b/src/leap/bitmask/util/pastebin.py
@@ -366,7 +366,9 @@ class PastebinAPI(object):
Usage Example::
from pastebin import PastebinAPI
x = PastebinAPI()
- details = x.user_details('453a994e0e2f1efae07f8759e59e075b', 'c57a18e6c0ae228cd4bd16fe36da381a')
+ details = x.user_details(
+ '453a994e0e2f1efae07f8759e59e075b',
+ 'c57a18e6c0ae228cd4bd16fe36da381a')
print details
<user>
<user_name>MonkeyPuzzle</user_name>
@@ -486,7 +488,8 @@ class PastebinAPI(object):
<paste>
<paste_key>DLiSspYT</paste_key>
<paste_date>1332714730</paste_date>
- <paste_title>Pastebin.py - Python 3.2 Pastebin.com API</paste_title>
+ <paste_title>Pastebin.py -
+ Python 3.2 Pastebin.com API</paste_title>
<paste_size>25300</paste_size>
<paste_expire_date>0</paste_expire_date>
<paste_private>0</paste_private>
@@ -609,7 +612,6 @@ class PastebinAPI(object):
def paste(self, api_dev_key, api_paste_code,
api_user_key=None, paste_name=None, paste_format=None,
paste_private=None, paste_expire_date=None):
-
"""Submit a code snippet to Pastebin using the new API.