Skip to content
Snippets Groups Projects
Commit 2f15e028 authored by Bahtiar Gadimov's avatar Bahtiar Gadimov
Browse files

Release omemo plugin version 0.4

parents 0c045f5e 64c390bf
No related branches found
No related tags found
No related merge requests found
Showing
with 1765 additions and 36 deletions
0.4 / 2016-01-21
==================
* Update README.md
* Fix #32: Add own devices as possible OMEMO partners.
* Fix one of the errors in #26
* Fix sqlite db intialization
* Use the standalone python-omemo library
* FIx LOG_DB errors / lost messages
* Move all OMEMO related parts to own dir
* Rename all links from kalkin/.. to omemo/...
* Update archlinux PKGBUILD to 0.3
0.3 / 2016-01-10
==================
* Save if OMEMO is enabled between restarts - #17
......
......@@ -41,20 +41,20 @@ contribute clone the git repository into your Gajim's plugin directory.
```shell
mkdir ~/.local/share/gajim/plugins -p
cd ~/.local/share/gajim/plugins
git clone https://github.com/kalkin/gajim-omemo
git clone https://github.com/omemo/gajim-omemo
```
## Support this project
I develop this project in my free time. Your donation allows me to spend more
time working on it and on free software generally.
My Bitcoin Address is: `1CnNM3Mree9hU8eRjCXrfCWV mX6oBnEfV1`
My Bitcoin Address is: `1CnNM3Mree9hU8eRjCXrfCWVmX6oBnEfV1`
[![Support Me via Flattr](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/thing/5038679)
## I found a bug
Please report it to the [issue
tracker](https://github.com/kalkin/gajim-omemo/issues). If you are experiencing
tracker](https://github.com/omemo/gajim-omemo/issues). If you are experiencing
misbehaviour please provide detailed steps to reproduce and debugging output.
Always mention the exact Gajim version.
......
......@@ -19,6 +19,8 @@
#
import logging
import os
import sqlite3
from common import caps_cache, gajim, ged
from common.pep import SUPPORTED_PERSONAL_USER_EVENTS
......@@ -37,12 +39,14 @@ AXOLOTL_MISSING = 'Please install python-axolotl.'
log = logging.getLogger('gajim.plugin_system.omemo')
try:
from .state import OmemoState
from omemo.state import OmemoState
HAS_AXOLOTL = True
except ImportError:
log.error(AXOLOTL_MISSING)
HAS_AXOLOTL = False
DB_DIR = gajim.gajimpaths.data_root
class OmemoPlugin(GajimPlugin):
......@@ -75,7 +79,9 @@ class OmemoPlugin(GajimPlugin):
OmemoState if it does not exist yet.
"""
if account not in self.omemo_states:
self.omemo_states[account] = OmemoState(account)
db_path = os.path.join(DB_DIR, 'omemo_' + account + '.db')
conn = sqlite3.connect(db_path, check_same_thread=False)
self.omemo_states[account] = OmemoState(conn)
return self.omemo_states[account]
@log_calls('OmemoPlugin')
......@@ -84,8 +90,7 @@ class OmemoPlugin(GajimPlugin):
On sign in announce OMEMO support for each account.
"""
account = show.conn.name
state = self.get_omemo_state(account)
self.announce_support(state)
self.announce_support(account)
@log_calls('OmemoPlugin')
def activate(self):
......@@ -183,9 +188,9 @@ class OmemoPlugin(GajimPlugin):
my_jid = gajim.get_jid_from_account(account_name)
if contact_jid == my_jid:
log.info(state.name + ' ⇒ Received own device_list:' + str(
log.info(account_name + ' ⇒ Received own device_list:' + str(
devices_list))
state.add_own_devices(devices_list)
state.add_own_devices(my_jid, devices_list)
if not state.own_device_id_published() or anydup(
state.own_devices):
......@@ -194,7 +199,7 @@ class OmemoPlugin(GajimPlugin):
# also remove duplicates
devices_list = list(set(state.own_devices))
devices_list.append(state.own_device_id)
self.publish_own_devices_list(state)
self.publish_own_devices_list(account_name, state)
else:
log.info(account_name + ' ⇒ Received device_list for ' +
contact_jid + ':' + str(devices_list))
......@@ -213,14 +218,14 @@ class OmemoPlugin(GajimPlugin):
return True
@log_calls('OmemoPlugin')
def publish_own_devices_list(self, state):
def publish_own_devices_list(self, account_name, state):
devices_list = state.own_devices
devices_list += [state.own_device_id]
log.debug(state.name + ' ⇒ Publishing own devices_list ' + str(
log.debug(account_name + ' ⇒ Publishing own devices_list ' + str(
devices_list))
iq = DeviceListAnnouncement(devices_list)
gajim.connections[state.name].connection.send(iq)
gajim.connections[account_name].connection.send(iq)
id_ = str(iq.getAttr('id'))
iq_ids_to_callbacks[id_] = lambda event: log.debug(event)
......@@ -231,7 +236,8 @@ class OmemoPlugin(GajimPlugin):
if account_name not in self.ui_list:
self.ui_list[account_name] = {}
state = self.get_omemo_state(account_name)
if contact_jid in state.device_ids:
my_jid = gajim.get_jid_from_account(account_name)
if contact_jid in state.device_ids or contact_jid == my_jid:
log.debug(account_name + " ⇒ Adding OMEMO ui for " + contact_jid)
omemo_enabled = state.encryption.is_active(contact_jid)
self.ui_list[account_name][contact_jid] = Ui(self, chat_control,
......@@ -274,18 +280,23 @@ class OmemoPlugin(GajimPlugin):
to_jid = recipient.jid
my_jid = gajim.get_jid_from_account(account)
for device_id in state.devices_without_sessions(to_jid):
self.fetch_device_bundle_information(state, to_jid, device_id)
self.fetch_device_bundle_information(account, state, to_jid,
device_id)
for device_id in state.own_devices_without_sessions(my_jid):
self.fetch_device_bundle_information(state, my_jid, device_id)
self.fetch_device_bundle_information(account, state, my_jid,
device_id)
@log_calls('OmemoPlugin')
def fetch_device_bundle_information(self, state, jid, device_id):
def fetch_device_bundle_information(self, account_name, state, jid,
device_id):
""" Fetch bundle information for specified jid, key, and create axolotl
session on success.
Parameters
----------
account_name : str
The account name
state : (OmemoState)
The OmemoState which is missing device bundle information
jid : str
......@@ -293,18 +304,19 @@ class OmemoPlugin(GajimPlugin):
device_id : int
The device_id for which we are missing an axolotl session
"""
log.debug(state.name + '→ Fetch bundle device ' + str(device_id) + '#'
log.debug(account_name + '→ Fetch bundle device ' + str(device_id) + '#'
+ jid)
iq = BundleInformationQuery(jid, device_id)
iq_id = str(iq.getAttr('id'))
iq_ids_to_callbacks[iq_id] = \
lambda stanza: self.session_from_prekey_bundle(state, stanza,
jid, device_id)
gajim.connections[state.name].connection.send(iq)
lambda stanza: self.session_from_prekey_bundle(account_name, state,
stanza, jid,
device_id)
gajim.connections[account_name].connection.send(iq)
@log_calls('OmemoPlugin')
def session_from_prekey_bundle(self, state, stanza, recipient_id,
device_id):
def session_from_prekey_bundle(self, account_name, state, stanza,
recipient_id, device_id):
""" Starts a session when a bundle information announcement is received.
......@@ -325,6 +337,8 @@ class OmemoPlugin(GajimPlugin):
Parameters:
-----------
account_name : str
The account name
state : (OmemoState)
The OmemoState used
stanza
......@@ -341,7 +355,7 @@ class OmemoPlugin(GajimPlugin):
return
if state.build_session(recipient_id, device_id, bundle_dict):
self.update_prekeys(state.name, recipient_id)
self.update_prekeys(account_name, recipient_id)
@log_calls('OmemoPlugin')
def update_prekeys(self, account, recipient_id):
......@@ -368,23 +382,23 @@ class OmemoPlugin(GajimPlugin):
Parameters
----------
account : str
The account name
the account name
See also
--------
4.3 Announcing bundle information:
http://conversations.im/xeps/multi-end.html#usecases-announcing
"""
state = self.get_omemo_state(account.name)
state = self.get_omemo_state(account)
iq = BundleInformationAnnouncement(state.bundle, state.own_device_id)
gajim.connections[state.name].connection.send(iq)
gajim.connections[account].connection.send(iq)
id_ = str(iq.getAttr("id"))
log.debug(account.name + " → Announcing OMEMO support via PEP")
log.debug(account + " → Announcing OMEMO support via PEP")
iq_ids_to_callbacks[id_] = lambda stanza: \
self.handle_announcement_result(stanza, state)
self.handle_announcement_result(account, stanza, state)
@log_calls('OmemoPlugin')
def handle_announcement_result(self, stanza, state):
def handle_announcement_result(self, account, stanza, state):
""" Updates own device list if announcement was successfull.
If the OMEMO support announcement was successfull update own device
......@@ -392,17 +406,20 @@ class OmemoPlugin(GajimPlugin):
Parameters
----------
account : str
the account name
stanza
The stanza object received from callback
state : (OmemoState)
The OmemoState used
"""
account = state.name
state = self.get_omemo_state(account)
if successful(stanza):
log.debug(account + ' → Publishing bundle was successful')
if not state.own_device_id_published():
log.warn(account + ' → Device list needs updating')
self.publish_own_devices_list(state)
self.publish_own_devices_list(account, state)
else:
log.debug(account + ' → Device list up to date')
else:
......@@ -414,9 +431,9 @@ class OmemoPlugin(GajimPlugin):
state = self.get_omemo_state(account)
devices_list = [state.own_device_id]
log.info(state.name + ' ⇒ Clearing devices_list ' + str(devices_list))
log.info(account + ' ⇒ Clearing devices_list ' + str(devices_list))
iq = DeviceListAnnouncement(devices_list)
connection = gajim.connections[state.name].connection
connection = gajim.connections[account].connection
if not connection: # not connected
return
connection.send(iq)
......@@ -435,8 +452,8 @@ class OmemoPlugin(GajimPlugin):
if not state.encryption.is_active(to_jid):
return False
try:
msg_dict = state.create_msg(
gajim.get_jid_from_account(account), to_jid, plaintext)
msg_dict = state.create_msg(gajim.get_jid_from_account(account),
to_jid, plaintext)
if not msg_dict:
return True
encrypted_node = OmemoMessage(msg_dict)
......
--ignore-dir
.tox
--ignore-dir
dist
--ignore-dir
.venv
--ignore-dir
.ropeproject
--ignore-dir
src/omemo.egg-info/
--ignore-file
ext:pyc
--ignore-file
match:.coverage.python
[bumpversion]
current_version = 0.1.0
commit = True
tag = True
[bumpversion:file:setup.py]
[bumpversion:file:docs/conf.py]
[bumpversion:file:src/omemo/__init__.py]
# This file exists so you can easily regenerate your project.
#
# `cookiepatcher` is a convenient shim around `cookiecutter`
# for regenerating projects (it will generate a .cookiecutterrc
# automatically for any template). To use it:
#
# pip install cookiepatcher
# cookiepatcher gh:ionelmc/cookiecutter-pylibrary project-path
#
# See:
# https://pypi.python.org/pypi/cookiecutter
#
# Alternatively, you can run:
#
# cookiecutter --overwrite-if-exists --config-file=project-path/.cookiecutterrc gh:ionelmc/cookiecutter-pylibrary
default_context:
appveyor: 'yes'
bin_name: 'omemo'
c_extension_cython: 'no'
c_extension_optional: 'no'
c_extension_support: 'no'
codacy: 'no'
codeclimate: 'no'
codecov: 'yes'
command_line_interface: 'no'
coveralls: 'no'
distribution_name: 'python-omemo'
email: 'bahtiar@gadimov.de'
full_name: 'Bahtiar `kalkin-` Gadimov'
github_username: 'kalkin'
landscape: 'no'
package_name: 'omemo'
project_name: 'Python OMEMO Library'
project_short_description: 'This is an implementation o*OMEMO Multi-End Message and Object Encryption** in Python.'
release_date: 'today'
repo_name: 'python-omemo'
requiresio: 'yes'
scrutinizer: 'no'
sphinx_theme: 'readthedocs'
test_matrix_configurator: 'no'
test_runner: 'pytest'
travis: 'yes'
version: '0.1.0'
website: 'https://github.com/omemo'
year: 'now'
[paths]
source = src
[run]
branch = True
source = src
parallel = true
[report]
show_missing = true
precision = 2
omit = *migrations*
# see http://editorconfig.org
root = true
[*]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 4
charset = utf-8
[*.{bat,cmd,ps1}]
end_of_line = crlf
*.py[cod]
# C extensions
*.so
# Packages
*.egg
*.egg-info
dist
build
eggs
.eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
lib
lib64
venv*/
pyvenv*/
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
.coverage.*
nosetests.xml
coverage.xml
htmlcov
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
.idea
*.iml
*.komodoproject
# Complexity
output/*.html
output/*/index.html
# Sphinx
docs/_build
.DS_Store
*~
.*.sw[po]
.build
.ve
.env
.cache
.pytest
.bootstrap
.appveyor.token
*.bak
language: python
python: '3.5'
sudo: false
env:
global:
- LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so
- SEGFAULT_SIGNALS=all
matrix:
- TOXENV=check
- TOXENV=py27-cover,codecov
- TOXENV=py27-nocov
- TOXENV=py33-cover,codecov
- TOXENV=py33-nocov
- TOXENV=py34-cover,codecov
- TOXENV=py34-nocov
- TOXENV=py35-cover,codecov
- TOXENV=py35-nocov
- TOXENV=pypy-cover,codecov
- TOXENV=pypy-nocov
before_install:
- python --version
- uname -a
- lsb_release -a
install:
- pip install tox
- virtualenv --version
- easy_install --version
- pip --version
- tox --version
script:
- tox -v
after_failure:
- more .tox/log/* | cat
- more .tox/*/log/* | cat
before_cache:
- rm -rf $HOME/.cache/pip/log
cache:
directories:
- $HOME/.cache/pip
notifications:
email:
on_success: never
on_failure: always
Authors
=======
* Bahtiar `kalkin-` Gadimov - https://github.com/kalkin
* Daniel Gultsch - https://github.com/inputmice
* Tarek Galal - https://github.com/tgalal (original axolotl store implementation)
Changelog
=========
0.1.0 (2016-01-11)
-----------------------------------------
* First release on PyPI.
.. _c4
=====================================
Collective Code Construction Contract
=====================================
The **Collective Code Construction Contract (C4)** is an evolution of the
`github.com Fork + Pull Model
<https://help.github.com/articles/using-pull-requests/>`_, aimed at providing an
optimal collaboration model for free software projects. This is revision 1 of
the C4 specification.
License
=======
Copyright (c) 2009-2015 Pieter Hintjens.
This Specification 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 Specification 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>.
Language
========
The key words "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL NOT**", "**SHOULD**",
"**SHOULD NOT**", "**RECOMMENDED**", "**MAY**", and "**OPTIONAL**" in this document are to be
interpreted as described in `RFC 2119 <https://tools.ietf.org/html/rfc2119>`_.
Goals
=====
C4 is meant to provide a reusable optimal collaboration model for open source
software projects. It has these specific goals:
- To maximize the scale of the community around a project, by reducing the
friction for new Contributors and creating a scaled participation model with
strong positive feedbacks;
- To relieve dependencies on key individuals by separating different skill sets
so that there is a larger pool of competence in any required domain;
- To allow the project to develop faster and more accurately, by increasing the
diversity of the decision making process;
- To support the natural life cycle of project versions from experimental
through to stable, by allowing safe experimentation, rapid failure, and
isolation of stable code;
- To reduce the internal complexity of project repositories, thus making it
easier for Contributors to participate and reducing the scope for error;
- To enforce collective ownership of the project, which increases economic
incentive to Contributors and reduces the risk of hijack by hostile entities.
Design
======
Preliminaries
-------------
- The project **SHALL** use the git distributed revision control system.
- The project **SHALL** be hosted on github.com or equivalent, herein called the
"Platform".
- The project **SHALL** use the Platform issue tracker.
- The project **SHOULD** have clearly documented guidelines for code style.
- A "Contributor" is a person who wishes to provide a patch, being a set of
commits that solve some clearly identified problem.
- A "Maintainer" is a person who merges patches to the project. Maintainers are
not developers; their job is to enforce process.
- Contributors **SHALL NOT** have commit access to the repository unless they are
also Maintainers.
- Maintainers **SHALL** have commit access to the repository.
- Everyone, without distinction or discrimination, **SHALL** have an equal right to
become a Contributor under the terms of this contract.
Licensing and Ownership
-----------------------
- The project **SHALL** use a share-alike license, such as the GPLv3 or a variant
thereof (LGPL, AGPL), or the MPLv2.
- All contributions to the project source code ("patches") **SHALL** use the same
license as the project.
- All patches are owned by their authors. There **SHALL NOT** be any copyright
assignment process.
- The copyrights in the project **SHALL** be owned collectively by all its
Contributors.
- Each Contributor **SHALL** be responsible for identifying themselves in the
project Contributor list.
Patch Requirements
------------------
- Maintainers and Contributors **MUST** have a Platform account and **SHOULD**
use their real names or a well-known alias.
- A patch **SHOULD** be a minimal and accurate answer to exactly one identified and
agreed problem.
- A patch **MUST** adhere to the code style guidelines of the project if these are
defined.
- A patch **MUST** adhere to the "Evolution of Public Contracts" guidelines defined
below.
- A patch **SHALL NOT** include non-trivial code from other projects unless the
Contributor is the original author of that code.
- A patch **MUST** compile cleanly and pass project self-tests on at least the
principle target platform.
- A patch commit message **SHOULD** consist of a single short (less than 50
character) line summarizing the change, optionally followed by a blank line
and then a more thorough description.
- A "Correct Patch" is one that satisfies the above requirements.
Development Process
-------------------
- Change on the project **SHALL** be governed by the pattern of accurately
identifying problems and applying minimal, accurate solutions to these
problems.
- To request changes, a user **SHOULD** log an issue on the project Platform issue
tracker.
- The user or Contributor **SHOULD** write the issue by describing the problem they
face or observe.
- The user or Contributor **SHOULD** seek consensus on the accuracy of their
observation, and the value of solving the problem.
- Users **SHALL NOT** log feature requests, ideas, suggestions, or any solutions to
problems that are not explicitly documented and provable.
- Thus, the release history of the project **SHALL** be a list of meaningful issues
logged and solved.
- To work on an issue, a Contributor **SHALL** fork the project repository and then
work on their forked repository.
- To submit a patch, a Contributor **SHALL** create a Platform pull request back to
the project.
- A Contributor **SHALL NOT** commit changes directly to the project.
- If the Platform implements pull requests as issues, a Contributor **MAY**
directly send a pull request without logging a separate issue.
- To discuss a patch, people **MAY** comment on the Platform pull request, on the
commit, or elsewhere.
- To accept or reject a patch, a Maintainer **SHALL** use the Platform interface.
- Maintainers **SHOULD NOT** merge their own patches except in exceptional cases,
such as non-responsiveness from other Maintainers for an extended period (more
than 1-2 days).
- Maintainers **SHALL NOT** make value judgments on correct patches.
- Maintainers **SHALL** merge correct patches from other Contributors rapidly.
- The Contributor **MAY** tag an issue as "Ready" after making a pull request for
the issue.
- The user who created an issue **SHOULD** close the issue after checking the patch
is successful.
- Maintainers **SHOULD** ask for improvements to incorrect patches and
**SHOULD** reject incorrect patches if the Contributor does not respond
constructively.
- Any Contributor who has value judgments on a correct patch **SHOULD** express
these via their own patches.
- Maintainers **MAY** commit changes to non-source documentation directly to the
project.
Creating Stable Releases
------------------------
- The project **SHALL** have one branch ("master") that always holds the latest
in-progress version and **SHOULD** always build.
- The project **SHALL NOT** use topic branches for any reason. Personal forks
**MAY** use topic branches.
- To make a stable release someone **SHALL** fork the repository by copying it and
thus become maintainer of this repository.
- Forking a project for stabilization **MAY** be done unilaterally and without
agreement of project maintainers.
- A stabilization project **SHOULD** be maintained by the same process as the main
project.
- A patch to a stabilization project declared "stable" **SHALL** be accompanied by
a reproducible test case.
Evolution of Public Contracts
-----------------------------
- All Public Contracts (APIs or protocols) **SHALL** be documented.
- All Public Contracts **SHOULD** have space for extensibility and experimentation.
- A patch that modifies a stable Public Contract **SHOULD** not break existing
applications unless there is overriding consensus on the value of doing this.
- A patch that introduces new features to a Public Contract **SHOULD** do so using
new names.
- Old names **SHOULD** be deprecated in a systematic fashion by marking new names
as "experimental" until they are stable, then marking the old names as
"deprecated".
- When sufficient time has passed, old deprecated names **SHOULD** be marked
"legacy" and eventually removed.
- Old names **SHALL NOT** be reused by new features.
- When old names are removed, their implementations **MUST** provoke an exception
(assertion) if used by applications.
Project Administration
----------------------
- The project founders **SHALL** act as Administrators to manage the set of project
Maintainers.
- The Administrators **SHALL** ensure their own succession over time by promoting
the most effective Maintainers.
- A new Contributor who makes a correct patch **SHALL** be invited to become a
Maintainer.
- Administrators **MAY** remove Maintainers who are inactive for an extended period
of time, or who repeatedly fail to apply this process accurately.
- Administrators **SHOULD** block or ban "bad actors" who cause stress and pain to
others in the project. This should be done after public discussion, with a
chance for all parties to speak. A bad actor is someone who repeatedly ignores
the rules and culture of the project, who is needlessly argumentative or
hostile, or who is offensive, and who is unable to self-correct their behavior
when asked to do so by others.
Further Reading
---------------
- Argyris' Models 1 and 2 - the goals of C4.1 are consistent with Argyris'
Model 2.
- Toyota Kata - covering the Improvement Kata (fixing problems one at a time)
and the Coaching Kata (helping others to learn the Improvement Kata).
Implementations
---------------
- The ZeroMQ community uses the C4.1 process for many projects.
- OSSEC uses the C4.1 process.
- The Machinekit community uses the C4.1 process.
This diff is collapsed.
graft docs
graft examples
graft src
graft ci
graft tests
include .bumpversion.cfg
include .coveragerc
include .cookiecutterrc
include .editorconfig
include .isort.cfg
include AUTHORS.rst
include CHANGELOG.rst
include CONTRIBUTING.rst
include COPYING
include README.rst
include tox.ini .travis.yml appveyor.yml .ackrc
global-exclude *.py[cod] __pycache__ *.so *.dylib
========
Overview
========
.. start-badges
.. list-table::
:stub-columns: 1
* - docs
- |docs|
* - tests
- | |travis| |appveyor| |requires|
| |codecov|
|
* - package
- |version| |downloads| |wheel| |supported-versions| |supported-implementations|
.. |docs| image:: https://readthedocs.org/projects/python-omemo/badge/?style=flat
:target: https://readthedocs.org/projects/python-omemo
:alt: Documentation Status
.. |travis| image:: https://travis-ci.org/omemo/python-omemo.svg?branch=master
:alt: Travis-CI Build Status
:target: https://travis-ci.org/omemo/python-omemo
.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/omemo/python-omemo?branch=master&svg=true
:alt: AppVeyor Build Status
:target: https://ci.appveyor.com/project/omemo/python-omemo
.. |requires| image:: https://requires.io/github/omemo/python-omemo/requirements.svg?branch=master
:alt: Requirements Status
:target: https://requires.io/github/omemo/python-omemo/requirements/?branch=master
.. |codecov| image:: https://codecov.io/github/omemo/python-omemo/coverage.svg?branch=master
:alt: Coverage Status
:target: https://codecov.io/github/omemo/python-omemo
.. |version| image:: https://img.shields.io/pypi/v/python-omemo.svg?style=flat
:alt: PyPI Package latest release
:target: https://pypi.python.org/pypi/python-omemo
.. |downloads| image:: https://img.shields.io/pypi/dm/python-omemo.svg?style=flat
:alt: PyPI Package monthly downloads
:target: https://pypi.python.org/pypi/python-omemo
.. |wheel| image:: https://img.shields.io/pypi/wheel/python-omemo.svg?style=flat
:alt: PyPI Wheel
:target: https://pypi.python.org/pypi/python-omemo
.. |supported-versions| image:: https://img.shields.io/pypi/pyversions/python-omemo.svg?style=flat
:alt: Supported versions
:target: https://pypi.python.org/pypi/python-omemo
.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/python-omemo.svg?style=flat
:alt: Supported implementations
:target: https://pypi.python.org/pypi/python-omemo
.. end-badges
This is an implementation **OMEMO Multi-End Message and Object Encryption** in Python.
Installation
============
::
pip install python-omemo
Documentation
=============
https://python-omemo.readthedocs.org/
Development
===========
To set up `python-omemo` for local development:
1. `Fork python-omemo on GitHub <https://github.com/omemo/python-omemo/fork>`_.
2. Clone your fork locally::
git clone git@github.com:your_name_here/python-omemo.git
3. Create a branch for local development::
git checkout -b name-of-your-bugfix-or-feature
Now you can make your changes locally.
4. Run all the checks, doc builder and spell checker with `tox <http://tox.readthedocs.org/en/latest/install.html>`_ one command::
tox
Tips
----
To run a subset of tests::
tox -e envname -- py.test -k test_myfeature
To run all the test environments in *parallel* (you need to ``pip install detox``)::
detox
Contributing
============
The **Python OMEMO** project direction is the sum of documented problems:
everybody is invited to describe and discuss a problem in the `issue
tracker <https://github.com/omemo/python-omemo/issues>`_. Contributed solutions
encourage participation.
Some problem fields we initially focus on are:
- Creation of a reusable python omemo implementation
- Reusability bu the `Gajim OMEMO plugin <https://github.com/omemo/gajim-omemo>`_
version: '{branch}-{build}'
build: off
cache:
- '%LOCALAPPDATA%\pip\Cache'
environment:
global:
WITH_COMPILER: 'cmd /E:ON /V:ON /C .\ci\appveyor-with-compiler.cmd'
matrix:
- TOXENV: check
PYTHON_HOME: C:\Python27
PYTHON_VERSION: '2.7'
PYTHON_ARCH: '32'
- TOXENV: 'py27-cover,codecov'
TOXPYTHON: C:\Python27\python.exe
PYTHON_HOME: C:\Python27
PYTHON_VERSION: '2.7'
PYTHON_ARCH: '32'
- TOXENV: 'py27-cover,codecov'
TOXPYTHON: C:\Python27-x64\python.exe
WINDOWS_SDK_VERSION: v7.0
PYTHON_HOME: C:\Python27-x64
PYTHON_VERSION: '2.7'
PYTHON_ARCH: '64'
- TOXENV: 'py27-nocov'
TOXPYTHON: C:\Python27\python.exe
PYTHON_HOME: C:\Python27
PYTHON_VERSION: '2.7'
PYTHON_ARCH: '32'
- TOXENV: 'py27-nocov'
TOXPYTHON: C:\Python27-x64\python.exe
WINDOWS_SDK_VERSION: v7.0
PYTHON_HOME: C:\Python27-x64
PYTHON_VERSION: '2.7'
PYTHON_ARCH: '64'
- TOXENV: 'py34-cover,codecov'
TOXPYTHON: C:\Python34\python.exe
PYTHON_HOME: C:\Python34
PYTHON_VERSION: '3.4'
PYTHON_ARCH: '32'
- TOXENV: 'py34-cover,codecov'
TOXPYTHON: C:\Python34-x64\python.exe
WINDOWS_SDK_VERSION: v7.1
PYTHON_HOME: C:\Python34-x64
PYTHON_VERSION: '3.4'
PYTHON_ARCH: '64'
- TOXENV: 'py34-nocov'
TOXPYTHON: C:\Python34\python.exe
PYTHON_HOME: C:\Python34
PYTHON_VERSION: '3.4'
PYTHON_ARCH: '32'
- TOXENV: 'py34-nocov'
TOXPYTHON: C:\Python34-x64\python.exe
WINDOWS_SDK_VERSION: v7.1
PYTHON_HOME: C:\Python34-x64
PYTHON_VERSION: '3.4'
PYTHON_ARCH: '64'
- TOXENV: 'py35-cover,codecov'
TOXPYTHON: C:\Python35\python.exe
PYTHON_HOME: C:\Python35
PYTHON_VERSION: '3.5'
PYTHON_ARCH: '32'
- TOXENV: 'py35-cover,codecov'
TOXPYTHON: C:\Python35-x64\python.exe
PYTHON_HOME: C:\Python35-x64
PYTHON_VERSION: '3.5'
PYTHON_ARCH: '64'
- TOXENV: 'py35-nocov'
TOXPYTHON: C:\Python35\python.exe
PYTHON_HOME: C:\Python35
PYTHON_VERSION: '3.5'
PYTHON_ARCH: '32'
- TOXENV: 'py35-nocov'
TOXPYTHON: C:\Python35-x64\python.exe
PYTHON_HOME: C:\Python35-x64
PYTHON_VERSION: '3.5'
PYTHON_ARCH: '64'
init:
- ps: echo $env:TOXENV
- ps: ls C:\Python*
install:
- python -u ci\appveyor-bootstrap.py
- '%PYTHON_HOME%\Scripts\virtualenv --version'
- '%PYTHON_HOME%\Scripts\easy_install --version'
- '%PYTHON_HOME%\Scripts\pip --version'
- '%PYTHON_HOME%\Scripts\tox --version'
test_script:
- '%WITH_COMPILER% %PYTHON_HOME%\Scripts\tox'
on_failure:
- ps: dir "env:"
- ps: get-content .tox\*\log\*
artifacts:
- path: dist\*
### To enable remote debugging uncomment this (also, see: http://www.appveyor.com/docs/how-to/rdp-to-build-worker):
# on_finish:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
"""
AppVeyor will at least have few Pythons around so there's no point of implementing a bootstrapper in PowerShell.
This is a port of https://github.com/pypa/python-packaging-user-guide/blob/master/source/code/install.ps1
with various fixes and improvements that just weren't feasible to implement in PowerShell.
"""
from __future__ import print_function
from os import environ
from os.path import exists
from subprocess import check_call
try:
from urllib.request import urlretrieve
except ImportError:
from urllib import urlretrieve
BASE_URL = "https://www.python.org/ftp/python/"
GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py"
GET_PIP_PATH = "C:\get-pip.py"
URLS = {
("2.7", "64"): BASE_URL + "2.7.10/python-2.7.10.amd64.msi",
("2.7", "32"): BASE_URL + "2.7.10/python-2.7.10.msi",
# NOTE: no .msi installer for 3.3.6
("3.3", "64"): BASE_URL + "3.3.3/python-3.3.3.amd64.msi",
("3.3", "32"): BASE_URL + "3.3.3/python-3.3.3.msi",
("3.4", "64"): BASE_URL + "3.4.3/python-3.4.3.amd64.msi",
("3.4", "32"): BASE_URL + "3.4.3/python-3.4.3.msi",
("3.5", "64"): BASE_URL + "3.5.0/python-3.5.0-amd64.exe",
("3.5", "32"): BASE_URL + "3.5.0/python-3.5.0.exe",
}
INSTALL_CMD = {
# Commands are allowed to fail only if they are not the last command. Eg: uninstall (/x) allowed to fail.
"2.7": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"],
["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]],
"3.3": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"],
["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]],
"3.4": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"],
["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]],
"3.5": [["{path}", "/quiet", "TargetDir={home}"]],
}
def download_file(url, path):
print("Downloading: {} (into {})".format(url, path))
progress = [0, 0]
def report(count, size, total):
progress[0] = count * size
if progress[0] - progress[1] > 1000000:
progress[1] = progress[0]
print("Downloaded {:,}/{:,} ...".format(progress[1], total))
dest, _ = urlretrieve(url, path, reporthook=report)
return dest
def install_python(version, arch, home):
print("Installing Python", version, "for", arch, "bit architecture to", home)
if exists(home):
return
path = download_python(version, arch)
print("Installing", path, "to", home)
success = False
for cmd in INSTALL_CMD[version]:
cmd = [part.format(home=home, path=path) for part in cmd]
print("Running:", " ".join(cmd))
try:
check_call(cmd)
except Exception as exc:
print("Failed command", cmd, "with:", exc)
if exists("install.log"):
with open("install.log") as fh:
print(fh.read())
else:
success = True
if success:
print("Installation complete!")
else:
print("Installation failed")
def download_python(version, arch):
for _ in range(3):
try:
return download_file(URLS[version, arch], "installer.exe")
except Exception as exc:
print("Failed to download:", exc)
print("Retrying ...")
def install_pip(home):
pip_path = home + "/Scripts/pip.exe"
python_path = home + "/python.exe"
if exists(pip_path):
print("pip already installed.")
else:
print("Installing pip...")
download_file(GET_PIP_URL, GET_PIP_PATH)
print("Executing:", python_path, GET_PIP_PATH)
check_call([python_path, GET_PIP_PATH])
def install_packages(home, *packages):
cmd = [home + "/Scripts/pip.exe", "install"]
cmd.extend(packages)
check_call(cmd)
if __name__ == "__main__":
install_python(environ['PYTHON_VERSION'], environ['PYTHON_ARCH'], environ['PYTHON_HOME'])
install_pip(environ['PYTHON_HOME'])
install_packages(environ['PYTHON_HOME'], "setuptools>=18.0.1", "wheel", "tox", "virtualenv>=13.1.0")
#!/usr/bin/env python
"""
Use the AppVeyor API to download Windows artifacts.
Taken from: https://bitbucket.org/ned/coveragepy/src/tip/ci/download_appveyor.py
# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
"""
from __future__ import unicode_literals
import argparse
import os
import requests
import zipfile
def make_auth_headers():
"""Make the authentication headers needed to use the Appveyor API."""
path = os.path.expanduser("~/.appveyor.token")
if not os.path.exists(path):
raise RuntimeError(
"Please create a file named `.appveyor.token` in your home directory. "
"You can get the token from https://ci.appveyor.com/api-token"
)
with open(path) as f:
token = f.read().strip()
headers = {
'Authorization': 'Bearer {}'.format(token),
}
return headers
def download_latest_artifacts(account_project, build_id):
"""Download all the artifacts from the latest build."""
if build_id is None:
url = "https://ci.appveyor.com/api/projects/{}".format(account_project)
else:
url = "https://ci.appveyor.com/api/projects/{}/build/{}".format(account_project, build_id)
build = requests.get(url, headers=make_auth_headers()).json()
jobs = build['build']['jobs']
print(u"Build {0[build][version]}, {1} jobs: {0[build][message]}".format(build, len(jobs)))
for job in jobs:
name = job['name']
print(u" {0}: {1[status]}, {1[artifactsCount]} artifacts".format(name, job))
url = "https://ci.appveyor.com/api/buildjobs/{}/artifacts".format(job['jobId'])
response = requests.get(url, headers=make_auth_headers())
artifacts = response.json()
for artifact in artifacts:
is_zip = artifact['type'] == "Zip"
filename = artifact['fileName']
print(u" {0}, {1} bytes".format(filename, artifact['size']))
url = "https://ci.appveyor.com/api/buildjobs/{}/artifacts/{}".format(job['jobId'], filename)
download_url(url, filename, make_auth_headers())
if is_zip:
unpack_zipfile(filename)
os.remove(filename)
def ensure_dirs(filename):
"""Make sure the directories exist for `filename`."""
dirname, _ = os.path.split(filename)
if dirname and not os.path.exists(dirname):
os.makedirs(dirname)
def download_url(url, filename, headers):
"""Download a file from `url` to `filename`."""
ensure_dirs(filename)
response = requests.get(url, headers=headers, stream=True)
if response.status_code == 200:
with open(filename, 'wb') as f:
for chunk in response.iter_content(16 * 1024):
f.write(chunk)
else:
print(u" Error downloading {}: {}".format(url, response))
def unpack_zipfile(filename):
"""Unpack a zipfile, using the names in the zip."""
with open(filename, 'rb') as fzip:
z = zipfile.ZipFile(fzip)
for name in z.namelist():
print(u" extracting {}".format(name))
ensure_dirs(name)
z.extract(name)
parser = argparse.ArgumentParser(description='Download artifacts from AppVeyor.')
parser.add_argument('--id',
metavar='PROJECT_ID',
default='omemo/python-omemo',
help='Project ID in AppVeyor.')
parser.add_argument('build',
nargs='?',
metavar='BUILD_ID',
help='Build ID in AppVeyor. Eg: master-123')
if __name__ == "__main__":
# import logging
# logging.basicConfig(level="DEBUG")
args = parser.parse_args()
download_latest_artifacts(args.id, args.build)
:: To build extensions for 64 bit Python 3, we need to configure environment
:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of:
:: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1)
::
:: To build extensions for 64 bit Python 2, we need to configure environment
:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of:
:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0)
::
:: 32 bit builds do not require specific environment configurations.
::
:: Note: this script needs to be run with the /E:ON and /V:ON flags for the
:: cmd interpreter, at least for (SDK v7.0)
::
:: More details at:
:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows
:: http://stackoverflow.com/a/13751649/163740
::
:: Author: Olivier Grisel
:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
SET COMMAND_TO_RUN=%*
SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows
SET WIN_WDK="c:\Program Files (x86)\Windows Kits\10\Include\wdf"
ECHO SDK: %WINDOWS_SDK_VERSION% ARCH: %PYTHON_ARCH%
IF "%PYTHON_VERSION%"=="3.5" (
IF EXIST %WIN_WDK% (
REM See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/
REN %WIN_WDK% 0wdf
)
GOTO main
)
IF "%PYTHON_ARCH%"=="32" (
GOTO main
)
SET DISTUTILS_USE_SDK=1
SET MSSdk=1
"%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION%
CALL "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release
:main
ECHO Executing: %COMMAND_TO_RUN%
CALL %COMMAND_TO_RUN% || EXIT 1
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment