diff options
author | Kali Kaneko <kali@leap.se> | 2015-09-24 15:09:58 -0400 |
---|---|---|
committer | Kali Kaneko <kali@leap.se> | 2015-09-24 15:09:58 -0400 |
commit | 08694af26b7b3d2e480c8379745dd5234315c87d (patch) | |
tree | b38ce71cc7073bb573db97ca0dfc0c6ba0aa860f | |
parent | ddc30afd194bb31a24cf5097fba8680721834b1f (diff) | |
parent | aa31828fca8bb64ace56f6f3b2b94f90ffced3c2 (diff) |
Merge tag '0.9.0rc3' into debian/experimental
Tag leap.bitmask version 0.9.0rc3
36 files changed, 980 insertions, 87 deletions
@@ -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 ++++++++++++++++++ @@ -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 @@ -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 @@ -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.
|