diff --git a/.gitignore b/.gitignore index c24a77ee1210bb6aa5fea41e530110220d41003b..4dd3e3f55e42be299f9cdb9d28531d4981b0bfe8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,19 @@ -*.pyc +.be/id-cache +bts.mbox build +.cache +.coverage +dist +doc/doctrees/ +doc/html/ +*.egg-info/ +.eggs/ man +monkeysign/_version.py presentation.html +.pybuild +*.pyc +/.python-version +.tox/ ui -bts.mbox -.be/id-cache -monkeysign/_version.py +_version.py diff --git a/.gitlab/issue_templates/bug.md b/.gitlab/issue_templates/bug.md new file mode 100644 index 0000000000000000000000000000000000000000..6b1222a146cc5e926a66200d1b15cfe928d7a71a --- /dev/null +++ b/.gitlab/issue_templates/bug.md @@ -0,0 +1,72 @@ +> Please provide a summary of the bug you encountered here. + +## Expected behavior + +> What you expected to happen + +## Actual behavior + +> What happened instead + +## Steps to reproduce + +> Try to reproduce the issue. Please describe every step you took to +> reproduce the issue. Make sure to run Monkeysign with `--debug` when +> you reproduce and paste the output below. + +1. step 1: collect underpants +2. step 2: ??? +3. step 3: profit! + +## Suggested fixes + +> If you have ideas about how to fix this, feel free to provide it +> here or remove this section. + +## Testsuite output + +> Please paste the output of `monkeysign --test` here: + +``` +$ monkeysign --test +``` + +## Environment details + +> Run `monkeysign --version`.If you are running 2.1.0, just paste the +> output here. If the monkeysign version is `??`, maybe you need to +> install `python-setuptools-scm`. +> +> Otherwise, paste the version number, but also: +> +> * ``lsb_release -b``: operating system name, version and codename +> (e.g. ``Debian GNU/Linux 8.4 (jessie)``) +> * ``uname -a``: kernel version, architecture and build dates (e.g. ``Linux +> marcos 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt25-1 (2016-03-06) +> x86_64 GNU/Linux``) +> * ``python --version`` +> * ``gpg --version`` +> +> If you are using the graphical interface, try to also include the +> versions of the following libraries: +> +> * GTK +> * PyGTK +> * ZBar +> * QRencode +> * PIL +> +> Also explain how was Monkeysign installed (Debian package, PIP, from git, etc). + +## Debugging output + +> When you reproduced the issue, you used the `--debug` flag, paste +> the output here: + +``` +$ monkeysign --debug ... +``` + +> Watch out, personnal information like key fingerprints or key +> material may show up in the output. Review the output before +> copying it here. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index c649078270623e527e3f897ec447fcfc0acca827..cf9e3eae387fbf198a299452e8aec3fb73c57014 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1,9 +1,129 @@ -Contributing -~~~~~~~~~~~~ +Contribute +~~~~~~~~~~ This section explains the various ways users can participate in the development of Monkeysign, or get support when they find problems. +.. _conduct: + +Code of conduct +=============== + +Our Pledge +---------- + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +Our Standards +------------- + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +Our Responsibilities +-------------------- + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +Scope +----- + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +Enforcement +----------- + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting one of the persons :ref:`listed below <conduct_contacts>` individually. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. Project maintainers are +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +Project maintainers are encouraged to follow the spirit of the `Django +Code of Conduct Enforcement Manual <enforcement_>`_ when receiving +reports. + +.. _enforcement: https://www.djangoproject.com/conduct/enforcement-manual/ + +.. _conduct_contacts: + +Contacts +-------- + +The following people have volunteered to be available to respond to +Code of Conduct reports. They have reviewed existing literature and +agree to follow the aforementioned process in good faith. They also +accept OpenPGP-encrypted email: + +* Antoine Beaupré <anarcat@debian.org> +* Daniel Kahn Gillmor <dkg@fifthhorseman.net> + +Attribution +----------- + +This Code of Conduct is adapted from the `Contributor Covenant <homepage_>`_, version 1.4, +available at `http://contributor-covenant.org/version/1/4 <version_>`_. + +.. _homepage: http://contributor-covenant.org +.. _version: http://contributor-covenant.org/version/1/4 + +Changes +------- + +The Code of Conduct was modified to refer to *project maintainers* +instead of *project team* and small paragraph was added to refer to +the Django enforcement manual. + +.. note:: We have so far determined that writing an explicit + enforcement policy is not necessary, considering the + available literature already available online and the + relatively small size of the Monkeysign community. This may + change in the future if the community grows larger. + + This code of conduct was adopted in 2016 by the Monkeysign + maintainers, see :issue:`54` for more details about the + discussion. + .. _schedule: Support schedule @@ -47,7 +167,7 @@ Each branch may be in one of those states: * Supported: The branch is supported, but no further development will be made on the branch. Only critical issues and security fixes are performed. -* Deprecated: users are strongly encouraged to upgrde to later +* Deprecated: users are strongly encouraged to upgrade to later versions. No further updates perform except for critical security issues. * Abandoned: the branch is completely abandoned. No further updates @@ -56,14 +176,22 @@ Each branch may be in one of those states: ====== =========== ==================================================================== Branch Status Notes ====== =========== ==================================================================== -0.x Abandoned explicitely unsupported. +0.x Abandoned explicitly unsupported. 1.x Deprecated supported until the release of Debian jessie, now only in Debian LTS -2.0.x Supported supported until the end of the Debian jessie -2.1.x Deprecated short lived support branch, superseded by 2.2.x -2.2.x Supported supported until the end of the Debian stretch +2.0.x Supported supported until the end of Debian jessie +2.1.x Abandoned short lived support branch, superseded by 2.2.x +2.2.x Supported supported until the end of Debian stretch 2.x Development new releases performed here, schedule to be clarified ====== =========== ==================================================================== +We try to keep the number of "supported" and "deprecated" branches to +two each, which means it is likely a "deprecated" branch gets +abandoned when a "supported" branch gets "deprecated". + +If you are interested in supporting one of those branches beyond the +current state, we would be glad to welcome you on the +team. :doc:`Contact us <support>`! + See also :doc:`history` for more information on past releases. Documentation @@ -107,6 +235,8 @@ install any special software. New translations from Weblate need to be updated in our source tree by hand, so do let us know if you make a new translation, by filing an issue in our `online issue tracker`_. +.. _online issue tracker: https://0xacab.org/monkeysphere/monkeysign/issues + .. note:: We have chosen `Weblate <http://weblate.org/>`_ instead of other solutions because it integrates well with our git-based workflow: translations on the site are stored as @@ -127,109 +257,15 @@ Bug reports We want you to report bugs you find in Monkeysign. It's an important part of contributing to a project, and all bug reports will be read and -replied to politely and professionally. - -Bugs used to be tracked with the -`bugs-everywhere <http://bugseverywhere.org/>`__ package, but this has -proven to be too difficult to use and not transparent enough to most -users, so we are now using -`Gitlab <https://0xacab.org/monkeysphere/monkeysign/issues>`__, where -new bug reports should be sent. - -A good bug report will include: - -* ``lsb_release -b``: operating system name, version and codename - (``Debian GNU/Linux 8.4 (jessie)``) -* ``uname -a``: kernel version, architecture and build dates (``Linux - marcos 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt25-1 (2016-03-06) - x86_64 GNU/Linux``) -* ``monkeysign --version`` and how it was installed -* ``python --version`` -* ``gpg --version`` -* the output of ``monkeysign --debug`` when the faulty behavior is found - -.. warning:: The output of the ``--debug`` shows public key material - used by Monkeysign. Special efforts have been made so - that private key material is never displayed (or in fact - accessed directly or copied) but you may want to avoid - publicly disclosing which keys you are signing because - that can reveal your social graph. If you are confident - the signed user will publish the results on the public - keyservers, this is not much of a concern. But otherwise, - you should leave that decision to that user. This is - particularly relevant if you do *not* want to publicly - certify this (e.g. if you are using the ``--local`` - flag). Do review the output before sending it in bug - reports. - -If you are using the graphical interface, try to also include the -versions of the following libraries: - -* GTK -* PyGTK -* ZBar -* QRencode -* PIL - -In newer Monkeysign versions (2.1.0 or later), the above (and more) is -included on backtraces and in the ``--version`` output. - -.. tip:: Please do make sure the bug you have found has not already - been reported elsewhere. Do review the existing issues in the - `online issue tracker - <https://0xacab.org/monkeysphere/monkeysign/issues>`_ and the - `Debian BTS for Monkeysign`_. - -.. note:: The GPG library used to do cryptographic operations was - written from scratch for Monkeysign because none of the - existing Python libraries supported key signing. In - retrospect, this was a mistake, and there are plans to - replace the builtin library with an external, - better-maintained one (see :issue:`22`). In the meantime, - there may be problems with exotic keys or new versions of - GnuPG. Do report those issues as bugs. - -Debian BTS ----------- - -You can also report bugs by email over the `Debian -BTS <http://bugs.debian.org/>`__, even if you are not using Debian. Use -the ``reportbug`` package to report a bug if you run Debian (or Ubuntu), -otherwise send an email to ``submit@bugs.debian.org``, with content like -this: - -:: - - To: submit@bugs.debian.org - From: you@example.com - Subject: fails to frobnicate - - Package: monkeysign - Version: 1.0 - - Monkeysign fails to frobnicate. - - I tried to do... - - I was expecting... - - And instead I had this backtrace... - - I am running Arch Linux 2013.07.01, Python 2.7.5-1 under a amd64 - architecture. - -See also the `complete -instructions <http://www.debian.org/Bugs/Reporting>`__ for more -information on how to use the Debian bugtracker. You can also browse the -existing bug reports in the `Debian BTS for -Monkeysign <http://bugs.debian.org/monkeysign>`_ there. +replied to politely and professionally. See the :doc:`support` section +for more information about troubleshooting and bug reporting. Bug triage ---------- Bug triage is a very useful contribution as well. You can review the `issues on 0xACAB <https://0xacab.org/monkeysphere/monkeysign/issues>`__ -or in the `Debian BTS for Monkeysign`_. What needs to be done +or in the `Debian BTS for Monkeysign <http://bugs.debian.org/monkeysign>`_. What needs to be done is, for every issue: - try to reproduce the bug, if it is not reproducible, tag it with @@ -254,14 +290,43 @@ to use the Debian BTS <https://www.debian.org/Bugs/Developer>`__. Patches ======= -Patches can be submitted through `merge -requests <https://0xacab.org/monkeysphere/monkeysign/merge_requests>`__ -on the `Gitlab site <https://0xacab.org/monkeysphere/monkeysign/>`__. +Patches can be submitted through `merge requests`_ on the `Gitlab +site`_. You will need to `contact the 0xACAB staff`_ to request access +before you can create a fork and a merge request. + +.. _Gitlab site: https://0xacab.org/monkeysphere/monkeysign/ +.. _merge requests: https://0xacab.org/monkeysphere/monkeysign/merge_requests +.. _contact the 0xACAB staff: https://0xacab.org/riseup/0xacab/issues/new?issue%5Bassignee_id%5D=&issue%5Btitle=fork%20permission%20request&issue%5Bdescription=I%20need%20permission%20to%20fork%20the%20Monkeysign%20repository%20to%20contribute%20to%20the%20project.%20Please%20grant%20me%20fork%20access.%20Thank%20you. If you prefer old school, offline email systems, you can also use the Debian BTS, as described above, or send patches to the mailing list for discussion. +Some guidelines for patches: + +* A patch should be a minimal and accurate answer to exactly one + identified and agreed problem. +* A patch must compile cleanly and pass project self-tests on at least + the principle target platform. +* A patch commit message must consist of a single short (less than 50 + characters) line stating the a summary of the change, followed by a + blank line and then a description of the problem being solved and + its solution, or a reason for the change. Write more information, + not less, in the commit log. + +Maintainers should not merge their own patches unless there is no +response from other maintainers within a reasonable time frame (1-2 +days). + +.. note:: Those guidelines were inspired by the `Collective Code + Construct Contract`_. The document was found to be a little + too complex and hard to read and wasn't adopted in its + entirety. See `those discussions + <https://github.com/zeromq/rfc/issues?utf8=%E2%9C%93&q=author%3Aanarcat%20>`_ + for more information. + +.. _Collective Code Construct Contract: https://rfc.zeromq.org/spec:42/C4/ + Unit tests ========== @@ -270,30 +335,32 @@ Unit tests should be ran before sending patches. They can be ran with was ``./test.py`` and only from the source tree). The tests expect a unicode locale, so if you do not have that configured -already, do set one like this: - -:: +already, set one like this, otherwise a part of the test suite will be +skipped:: export LANG=C.UTF-8 monkeysign --test It is possible that some keys used in the tests expire. The built-in keys do not have specific expiry dates, but some keys are provided to -test some corner cases and *those* keys may have new expiration dates. - -To renew the keys, try: +test some corner cases and *those* keys may have new expiration +dates. Those tests should be skipped when the key expire, but the keys +should eventually be renewed. -:: +To renew the keys, try:: mkdir ~/.gpg-tmp chmod 700 ~/.gpg-tmp - gpg --homedir ~/.gpg-tmp --import 7B75921E.asc + gpg --homedir ~/.gpg-tmp --import monkeysign/tests/files/7B75921E.asc gpg --homedir ~/.gpg-tmp --refresh-keys 8DC901CE64146C048AD50FBB792152527B75921E - gpg --homedir ~/.gpg-tmp --export-options export-minimal --armor --export 8DC901CE64146C048AD50FBB792152527B75921E > 7B75921E.asc + gpg --homedir ~/.gpg-tmp --export-options export-minimal --armor --export 8DC901CE64146C048AD50FBB792152527B75921E > monkeysign/tests/files/7B75921E.asc + +Once that is done, the ``@skipIfDatePassed`` tests need to be adjusted +to not be skipped anymore. It is also possible the key is just expired and there is no replacement. In this case the solution is to try and find a similar test case and -replace the key, or simply disable that test. +replace the key, or simply skip that test. Debian packaging ================ @@ -310,6 +377,15 @@ A workaround is to hardcode the version with:: Release process =============== +To build a Monkeysign release, you will need to have a few tools +already installed, namely the Python packages ``wheel``, +``setuptools`` and ``setuptools-scm``. We also assume you use the +following Debian packages, although you may be able to work around +those: ``devscripts``, ``git``, ``git-buildpackage``, ``pip`` and +``twine``. In Debian, this should get you started:: + + sudo apt install python-wheel python-setuptools python-setuptools-scm devscripts git git-buildpackage python-pip twine + 1. make sure tests pass:: ./scripts/monkeysign --test @@ -334,10 +410,10 @@ Release process monkeysign --version monkeysign --test monkeyscan + dpkg --remove monkeysign 6. build and test Python "wheel":: - dpkg --remove monkeysign python setup.py bdist_wheel pip install dist/*.whl monkeysign --version diff --git a/debian/changelog b/debian/changelog index 3a0bddb49992c7ae6160f890632711ef047a5511..db965100f9820ba665ece25e9808741bce3d4edf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,60 @@ +monkeysign (2.2.3) unstable; urgency=medium + + [ Simon Fondrie-Teitler ] + * Don't escape percent signs that are actually required in default mua command + + [ Antoine Beaupré ] + * some small improvements to the bug issue template + * create 2.2.x branch officially + * silence errors in test suite with GnuPG 2 + + -- Antoine Beaupré <anarcat@debian.org> Tue, 24 Jan 2017 15:40:35 -0500 + +monkeysign (2.2.2) unstable; urgency=medium + + [ Antoine Beaupré ] + * explicitly depend on socks, seems like pybuild doesn't puck up the + depends (Closes: #847716) + * forgot some future tests failures (Closes: #841115) + * properly redirect version information + * mention --test in bug report guidelines + * clarify support schedule, fix typos + * abandon 2.1.x, tell people how to support more + * indicate that you need to request access to create merge requests + * document the new test skipping features + * give proper credits to documenters + * add credits section + * fix trove classifier + * output the parsed qrcode data when verbose + * do not load default config files in tests + * adopt covenant code of conduct + * patches merging guidelines + * refer to modernPGP manuals + * move code of conducts contacts to a special section + + [ Simon Fondrie-Teitler ] + * Add right click menu with print/save to qr code + * Don't attempt to sign a user's own key + * Make message more friendly + * add test for signing one's own key + * lowercase k in OpenPGPkey __repr__ + * Add Simon to authors file + + [ Tobias Mueller ] + * gpg: Use os.path.expanduser instead of the environment variable + + -- Antoine Beaupré <anarcat@debian.org> Thu, 15 Dec 2016 11:04:13 -0500 + +monkeysign (2.2.1) unstable; urgency=medium + + * fix socks dependency specification: it is a runtime, not just + build-time, dependency + * mark as production-ready in python classification + * skip another test that requires network during build + * run CI tests with --debug to ease future debugging + + -- Antoine Beaupré <anarcat@debian.org> Sat, 15 Oct 2016 09:18:21 -0400 + monkeysign (2.2.0) unstable; urgency=medium * fix tests with Debian CI diff --git a/debian/control b/debian/control index ff9d57129344626258201decf4190c2def6d26a6..b1587325e4f99c785dc42fef90f7695ab283bf54 100644 --- a/debian/control +++ b/debian/control @@ -30,6 +30,7 @@ Architecture: all Depends: ${misc:Depends} , ${python:Depends} , python-pkg-resources + , python-socks , gnupg , gnupg-agent , dirmngr @@ -40,20 +41,20 @@ Recommends: python-qrencode , python-mock Suggests: monkeysign-doc Description: OpenPGP key signing and exchange for humans - monkeysign is a tool to overhaul the OpenPGP keysigning experience + monkeysign is a project to overhaul the OpenPGP keysigning experience and bring it closer to something that most primates can understand. . - The project makes use of cheap digital cameras and the type of bar - code known as a QRcode to provide a human-friendly yet still-secure - keysigning experience. + To achieve this goal, it makes use of cheap digital cameras and the + type of bar code known as a QRcode to provide a human-friendly yet + still-secure keysigning experience. . No more reciting tedious strings of hexadecimal characters. And, you can build a little rogue's gallery of the people that you have met and exchanged keys with! . - Monkeysign is the commandline signing software, a caff - replacement. Monkeyscan is the graphical user interface that scans - qrcodes. + Monkeysign is also the name of it's commandline signing software, a + caff replacement. Monkeyscan is the graphical user interface that + scans qrcodes. Package: monkeysign-doc Architecture: all @@ -64,19 +65,19 @@ Replaces: monkeysign (<< 2.1.0) Breaks: monkeysign (<< 2.1.0) Section: doc Description: OpenPGP key signing and exchange for humans (documentation) - monkeysign is a tool to overhaul the OpenPGP keysigning experience + monkeysign is a project to overhaul the OpenPGP keysigning experience and bring it closer to something that most primates can understand. . - The project makes use of cheap digital cameras and the type of bar - code known as a QRcode to provide a human-friendly yet still-secure - keysigning experience. + To achieve this goal, it makes use of cheap digital cameras and the + type of bar code known as a QRcode to provide a human-friendly yet + still-secure keysigning experience. . No more reciting tedious strings of hexadecimal characters. And, you can build a little rogue's gallery of the people that you have met and exchanged keys with! . - Monkeysign is the commandline signing software, a caff - replacement. Monkeyscan is the graphical user interface that scans - qrcodes. + Monkeysign is also the name of it's commandline signing software, a + caff replacement. Monkeyscan is the graphical user interface that + scans qrcodes. . This package ships with the builtin documentation. diff --git a/debian/monkeysign.bug-script b/debian/monkeysign.bug-script index 677fd987d7addb4b29bb039f64555ae2bd97c665..bdff7d1b8f13613357ff0c7bf1cbce57549f5204 100644 --- a/debian/monkeysign.bug-script +++ b/debian/monkeysign.bug-script @@ -4,14 +4,18 @@ printf "\ndetailed monkeysign version information\n" >&3 # first try with monkeyscan, as it has everything monkeysign shows, but # with extra GUI information # if it fails, it will show why and then monkeysign will run normally -monkeyscan --version --debug >&3 || monkeysign --version --debug >&3 +monkeyscan --version --debug 2>&3 || monkeysign --version --debug 2>&3 cat >&3 <<EOF -please also include a backtrace and full --debug information +please also include a backtrace and full --debug information in case +of a crash or any failure. WARNING: make sure you review the information included in the output for confidential information. secret key material should never show up in Monkeysign output, but public key material, including user identies like pictures and email addresses may be shown. + +also include the output of monkeysign --test if you run Monkeysign +older than 2.1. EOF diff --git a/debian/tests/control b/debian/tests/control index e6157aabcd585c2c6f5d6578a1b20a07ba47bc96..9c82ea00e82ebf5c912e28fd161192b156f7265b 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -1,3 +1,3 @@ -Test-command: monkeysign --test +Test-command: monkeysign --debug --test Depends: @, python-mock Restrictions: allow-stderr diff --git a/doc/conf.py b/doc/conf.py index de186505196c17fb0960b92db76d0c301c906d7a..bf64ebde26f4778424b8e7e047678b6d48562545 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -33,19 +33,32 @@ templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' +# markdown support: http://blog.readthedocs.com/adding-markdown-support/ +import sphinx +if sphinx.version_info > (1,3,): + source_suffix = ['.rst', '.md'] +else: + print "WARNING: can't set source_suffix as you are running an older Sphinx version (< 1.3)" +try: + from recommonmark.parser import CommonMarkParser + source_parsers = {'.md': CommonMarkParser} +except ImportError: + print "WARNING: no markdown support found, bits of documentation will be missing" + # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' -# General information about the project. -project = u'Monkeysign' -copyright = u'2014, Antoine Beaupré' - # look for monkeysign in the parent directory sys.path.insert(0, os.path.dirname(__file__) + '/..') from monkeysign import __version__ as version +from monkeysign import __documenters__ + +# General information about the project. +project = u'Monkeysign' +copyright = u'2014-2016, %s and %s' % (u",".join(__documenters__[2:-1]), __documenters__[-1]) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/doc/credits.rst b/doc/credits.rst new file mode 100644 index 0000000000000000000000000000000000000000..3fa47ddc691be2679989ff9ad8c3c9287c338439 --- /dev/null +++ b/doc/credits.rst @@ -0,0 +1,8 @@ +========= + Credits +========= + +Those people are the ones who made Monkeysign possible. + +.. literalinclude:: ../monkeysign/__init__.py + :start-after: credits-start diff --git a/doc/glossary.rst b/doc/glossary.rst index 8c0e1c2084059437ce96acca5893a7c4e181565e..f3962dc4294970e49150669953cd29915488a327 100644 --- a/doc/glossary.rst +++ b/doc/glossary.rst @@ -31,3 +31,7 @@ In this documentation, the following definitions are used: A computer program used to read, compose and send email, normally ran on user computers. See :wikipedia:`Mail User Agent` for more information. + +We also try to adhere to the `Modern PGP <http://modernpgp.org/>`_ +`terminology <https://github.com/ModernPGP/terminology>`_ when +possible. diff --git a/doc/index.rst b/doc/index.rst index 4d1a86e9b6226e1d509534053c55210ad6fbc0c5..f6955041c489f776303b8f3ea2d54078d5db8b7d 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -10,13 +10,14 @@ install usage + support contributing history api ui-mockups/index glossary + credits * :ref:`genindex` * :ref:`modindex` * :ref:`search` - diff --git a/doc/install.rst b/doc/install.rst index cc5ab49069a1f4ecd72425adb8360c87365c6aa8..6576bf265473af01867e68c6582bcb5cc286e424 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -1,5 +1,5 @@ -Installing -========== +Install +======= Monkeysign can be installed in various ways, depending on which platform you are using. You can install Monkeysign: diff --git a/doc/issue_template.md b/doc/issue_template.md new file mode 120000 index 0000000000000000000000000000000000000000..df52e3a26e5a5823a4c5b840951ba5f2b43c9c91 --- /dev/null +++ b/doc/issue_template.md @@ -0,0 +1 @@ +../.gitlab/issue_templates/bug.md \ No newline at end of file diff --git a/doc/presentation.rst b/doc/presentation.rst index 262cda28ad7f344ffb8a548dae843d64dfcb8da1..e659f0bfc193ee38b6493736fc00e0c3bea43853 100644 --- a/doc/presentation.rst +++ b/doc/presentation.rst @@ -1,3 +1,8 @@ +.. to be built separately, so silence warnings about it missing from + toctrees: + +:orphan: + Monkeysign: OpenPGP key exchange for humans =========================================== diff --git a/doc/support.rst b/doc/support.rst new file mode 100644 index 0000000000000000000000000000000000000000..95f42699309226eda4146acb4718a02f3241af96 --- /dev/null +++ b/doc/support.rst @@ -0,0 +1,158 @@ +========= + Support +========= + +If you have problems or question using Monkeysign, there are several +options at your disposal: + +* Try to troubleshoot the issue yourself +* Write to the mailing list +* Chat on IRC +* File bug reports + +We of course welcome other contributions like documentation, +translations and patches, see the :doc:`contributing` guide for more +information on how to contribute to the project. + +Troubleshooting +--------------- + +The basic way to troubleshoot Monkeysign is to run the same command as +you did when you had an error with the ``--verbose`` or, if that +doesn't yield satisfactory results, with the ``--debug`` output. + +.. note:: The debug output outputs a lot of information, as it shows + the OpenPGP key material as it is exchanged with GnuPG. It + may be confusing for new users. + +If you suspect there is a bug in Monkeysign specific to your +environment, you can also try to see if it is reproducible within the +test suite with ``monkeysign --test``. From there, you can either file +a bug report or try to fix the issue yourself, see the +:doc:`contributing` section for more information. + +Otherwise, see below for more options to get support. + +Mailing list +------------ + +Anyone can write to the mailing list at +monkeysphere@lists.riseup.net. You can `browse the archives +<https://lists.riseup.net/www/arc/monkeysphere>`_ before posting to +see if your question has already been answered. Thanks to `Riseup.net +<https://riseup.net/>`_ for graciously hosting our mailing list. + +.. tip:: We encourage you to `donate to Riseup + <https://riseup.net/en/donate>`_ to support the Monkeysign + project, as we use several parts of their infrastructure to + develop Monkeysign. + +Note that the mailing list is for the larger `Monkeysphere project +<http://web.monkeysphere.info/>`_ so if you subscribe, you should +expect discussions to go beyond only Monkeysign. Furthermore, when you +write to the mailing list, you should explicitly mention that you are +talking about Monkeysign. + +Chat +---- + +We are often present in realtime in the ``#monkeysphere`` channel of +the `OFTC network <https://www.oftc.net/>`_. You can join the channel +using `this link <ircs://irc.oftc.net/monkeysphere>`_ or `this web +interface +<http://webchat.oftc.net/?nick=monkey.&channels=monkeysphere&prompt=1>`_. + +.. raw:: html + + <iframe src="http://webchat.oftc.net/?nick=monkey.&channels=monkeysphere&prompt=1" width="647" height="400"></iframe> + +Bug reports +----------- + +We want you to report bugs you find in Monkeysign. It's an important +part of contributing to a project, and all bug reports will be read and +replied to politely and professionally. + +We are using `0xACAB.org's Gitlab instance +<https://0xacab.org/monkeysphere/monkeysign/issues>`__ to manage +issues, and this is where bug reports should be sent. Some issues are +also documented by Debian users directly. + +.. tip:: A few tips on how to make good bug reports: + + * Before you report a new bug, review the existing issues in + the `online issue tracker`_ and the `Debian BTS for + Monkeysign`_ to make sure the bug has not already been + reported elsewhere. + + * The first aim of a bug report is to tell the developers + exactly how to reproduce the failure, so try to reproduce + the issue yourself and describe how you did that. + + * If that is not possible, just try to describe what went wrong in + detail. Write down the error messages, especially if they + have numbers. + + * Take the necessary time to write clearly and precisely. Say + what you mean, and make sure it cannot be misinterpreted. + + * Include the output of ``monkeysign --test``, ``monkeysign + --version`` and ``monkeysign --debug`` in your bug + reports. See the :doc:`issue template <issue_template>` for + more details about what to include in bug reports. + + If you wish to read more about issues regarding communication + in bug reports, you can read `How to Report Bugs + Effectively`_ which takes about 30 minutes. + +.. _online issue tracker: https://0xacab.org/monkeysphere/monkeysign/issues +.. _How to Report Bugs Effectively: http://www.chiark.greenend.org.uk/~sgtatham/bugs.html + +.. warning:: The output of the ``--debug`` shows public key material + used by Monkeysign. Special efforts have been made so + that private key material is never displayed (or in fact + accessed directly or copied) but you may want to avoid + publicly disclosing which keys you are signing because + that can reveal your social graph. If you are confident + the signed user will publish the results on the public + keyservers, this is not much of a concern. But otherwise, + you should leave that decision to that user. This is + particularly relevant if you do *not* want to publicly + certify this (e.g. if you are using the ``--local`` + flag). Do review the output before sending it in bug + reports. + +Debian BTS +~~~~~~~~~~ + +You can also report bugs by email over the `Debian +BTS <http://bugs.debian.org/>`__, even if you are not using Debian. Use +the ``reportbug`` package to report a bug if you run Debian (or Ubuntu), +otherwise send an email to ``submit@bugs.debian.org``, with content like +this: + +:: + + To: submit@bugs.debian.org + From: you@example.com + Subject: fails to frobnicate + + Package: monkeysign + Version: 1.0 + + Monkeysign fails to frobnicate. + + I tried to do... + + I was expecting... + + And instead I had this backtrace... + + I am running Arch Linux 2013.07.01, Python 2.7.5-1 under a amd64 + architecture. + +See also the `complete +instructions <http://www.debian.org/Bugs/Reporting>`__ for more +information on how to use the Debian bugtracker. You can also browse the +existing bug reports in the `Debian BTS for +Monkeysign <http://bugs.debian.org/monkeysign>`_ there. diff --git a/doc/usage.rst b/doc/usage.rst index 230d0297b1b8719a6ddf910dc0fd7793a62e5017..c825a5ae98881b422b41e3d1d0de5412815ff8df 100644 --- a/doc/usage.rst +++ b/doc/usage.rst @@ -1,4 +1,4 @@ -Using +Usage ===== Monkeysign comes in two different interfaces: a commandline interface @@ -141,6 +141,10 @@ examples of known working configurations. monkeysign --mua "thunderbird -compose to=%(to)s,subject=%(subject)s,body=%(body)s,attachment=%(attach)s" [...] + .. note:: Thunerbird fails to respect the attachment parameter in + versions before 52.1.1, see :bts:`837771` for more + details. + * Mutt:: monkeysign --mua "mutt -a %(attach)s -s %(subject)s -i %(body)s %(to)s" [...] diff --git a/monkeysign/__init__.py b/monkeysign/__init__.py index 0f61ba545d852b83580494c842d6491b23bac8fa..850a8cb30957ed835d37f15f4e08f5efbe5724c2 100644 --- a/monkeysign/__init__.py +++ b/monkeysign/__init__.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- +from __future__ import print_function, unicode_literals + __description__ = 'OpenPGP key exchange for humans' __long_description__ = """ monkeysign is a tool to overhaul the OpenPGP keysigning experience and @@ -46,6 +48,12 @@ __license__ = """ __website__ = 'http://web.monkeysphere.info/monkeysign' __documentation__ = 'http://monkeysign.readthedocs.io/en/' + __version__ +# hack to include the credits in the documentation +# maybe this should be parsed from a AUTHORS file instead, see +# https://0xacab.org/monkeysphere/monkeysign/issues/56 +# if you feel comptent to respond to Code of Conduct reports, +# make sure you add your email address below +# credits-start __authors__ = ['In alphabetical order:', '', 'Antoine Beaupré', @@ -55,6 +63,7 @@ __authors__ = ['In alphabetical order:', 'Kristian Fiskerstrand', 'Philip Jägenstedt', 'Ramakrishnan Muthukrishnan', + 'Simon Fondrie-Teitler', 'Tobias Mueller', ] __documenters__ = ['In alphabetical order:', diff --git a/monkeysign/cli.py b/monkeysign/cli.py index 9d23d2769dfc10b3d794c72b2dcf127eff6c6a85..ecce7d24dff022be9f233c4585e333a8cc7da468 100644 --- a/monkeysign/cli.py +++ b/monkeysign/cli.py @@ -22,6 +22,7 @@ import locale import sys import os import getpass +import logging if sys.version_info < (3,): input = raw_input @@ -29,6 +30,8 @@ if sys.version_info < (3,): from monkeysign.ui import MonkeysignUi import monkeysign.translation +logger = logging.getLogger(__name__) + class MonkeysignCli(MonkeysignUi): """sign a key in a safe fashion. @@ -53,11 +56,11 @@ passwords.""" os.environ['GPG_TTY'] = os.ttyname(sys.stdin.fileno()) except OSError as e: if e.errno == errno.ENOTTY: - self.warn(_('cannot find your TTY, GPG may freak out if you do not set the GPG_TTY environment')) + logger.warning(_('cannot find your TTY, GPG may freak out if you do not set the GPG_TTY environment')) else: raise else: - self.log(_('reset GPG_TTY to %s') % os.environ['GPG_TTY']) + logger.info(_('reset GPG_TTY to %s'), os.environ['GPG_TTY']) # 1. fetch the key into a temporary keyring self.find_key() @@ -65,7 +68,7 @@ passwords.""" # 2. copy the signing key secrets into the keyring self.copy_secrets() - self.warn(_('Preparing to sign with this key\n\n%s') % self.signing_key) + logger.warning(_('Preparing to sign with this key\n\n%s'), self.signing_key) # 3. for every user id (or all, if -a is specified) # 3.1. sign the uid, using gpg-agent @@ -108,8 +111,8 @@ passwords.""" # workaround http://bugs.python.org/issue7768 pattern = input(prompt.encode(sys.stdout.encoding or locale.getpreferredencoding(True))) - while not (pattern in allowed_uids or (pattern.isdigit() and int(pattern)-1 in list(range(0,len(allowed_uids))))): - print(_('invalid uid')) + while not (pattern in allowed_uids or (pattern.isdigit() and int(pattern)-1 in range(0,len(allowed_uids)))): + logger.warning(_('invalid uid')) pattern = input(prompt.encode(sys.stdout.encoding or locale.getpreferredencoding(True))) if pattern.isdigit(): pattern = allowed_uids[int(pattern)-1] diff --git a/monkeysign/gpg.py b/monkeysign/gpg.py index 0f5a1f02456da06442617eac49d3d4c35105dfaf..c6b9421cd12d7c95b10000d35f935a8e3319e784 100644 --- a/monkeysign/gpg.py +++ b/monkeysign/gpg.py @@ -72,11 +72,14 @@ from __future__ import print_function import errno import os, tempfile, shutil, subprocess, re from datetime import datetime +import logging import io import monkeysign.translation +logger = logging.getLogger(__name__) + class Context(): """Python wrapper for GnuPG @@ -104,13 +107,10 @@ class Context(): 'with-colons': None, 'with-fingerprint': None, 'fixed-list-mode': None, + 'no-verbose': None, 'list-options': 'show-sig-subpackets,show-uid-validity,show-unusable-uids,show-unusable-subkeys,show-keyring,show-sig-expire', } - # whether to paste output here and there - # if not false, needs to be a file descriptor - debug = False - def __init__(self): self.options = dict(Context.options) # copy @@ -128,7 +128,7 @@ class Context(): if option in self.options: del self.options[option] else: - return false + return False def build_command(self, command): """internal helper to build a proper gpg commandline @@ -179,6 +179,7 @@ class Context(): we can optionnally watch for a confirmation pattern on the statusfd. """ + logger.debug('command: %s', self.build_command(command)) proc = subprocess.Popen(self.build_command(command), # nosec stdin=subprocess.PIPE, stdout=subprocess.PIPE, @@ -187,9 +188,7 @@ class Context(): self.stdout = self.stdout.decode('utf-8') self.stderr = self.stderr.decode('utf-8') self.returncode = proc.returncode - if self.debug: - print('command:', self.build_command(command), file=self.debug) - print('ret:', self.returncode, 'stdout:', self.stdout, 'stderr:', self.stderr, file=self.debug) + logger.debug('ret: %s stdout: %s stderr: %s', self.returncode, self.stdout, self.stderr) return proc.returncode == 0 def seek_pattern(self, fd, pattern): @@ -208,11 +207,11 @@ class Context(): line = fd.readline().decode('utf-8') match = re.search(pattern, line) while line and not match: - if self.debug: print("skipped:", line, end=' ', file=self.debug) - line = fd.readline().decode('utf-8') + logger.debug("skipped: %s", line) + line = fd.readline() match = re.search(pattern, line) if match: - if self.debug: print("FOUND:", line, end=' ', file=self.debug) + logger.debug("FOUND: %s", line) return match else: raise GpgProtocolError(self.returncode, _("could not find pattern '%s' in input, last skipped '%s'") % (pattern, line)) @@ -241,14 +240,16 @@ class Context(): ignored = ('[GNUPG:] KEYEXPIRED', '[GNUPG:] SIGEXPIRED', '[GNUPG:] KEY_CONSIDERED', 'gpg: ') while line and line.startswith(ignored): - if self.debug: print("IGNORED:", line, end=' ', file=self.debug) - line = fd.readline().decode('utf-8') + logger.debug("IGNORED: %s", line) + line = fd.readline() match = re.search(pattern, line) - if self.debug: - if match: print("FOUND:", line, end=' ', file=self.debug) - else: print("SKIPPED:", line, end=' ', file=self.debug) + if match: + logger.debug("FOUND: %s", line) + else: + logger.debug("SKIPPED: %s",line) + if not match: raise GpgProtocolError(self.returncode, 'expected "%s", found "%s"' % (pattern, line)) return match @@ -266,8 +267,7 @@ class Context(): but really, the pipes are often setup outside of here so the fd is hardcoded here """ - if self.debug: - print("WROTE:", message, file=self.debug) + logging.debug("WROTE:%s", message) fd.write(message) fd.flush() @@ -311,7 +311,7 @@ class Keyring(): if homedir is not None: self.context.set_option('homedir', homedir) else: - homedir = os.environ['HOME'] + '/.gnupg' + homedir = os.path.join(os.path.expanduser("~"), '.gnupg') if 'GNUPGHOME' in os.environ: homedir = os.environ['GNUPGHOME'] self.homedir = homedir @@ -370,7 +370,7 @@ class Keyring(): def verify_file(self, sigfile, filename): self.context.call_command(['verify', sigfile, filename]) - with StringIO(self.context.stderr.decode('utf-8')) as fd: + with io.StringIO(self.context.stderr.decode('utf-8')) as fd: try: self.context.seek(fd, 'VALIDSIG') except GpgProtocolError: @@ -473,8 +473,7 @@ class Keyring(): def del_uid(self, fingerprint, pattern): command = self.context.build_command(['edit-key', fingerprint]) - if self.context.debug: - print('command:', command, file=self.context.debug) + logger.debug('command: %s', command) proc = subprocess.Popen(command, # nosec stdin=subprocess.PIPE, stdout=subprocess.PIPE, @@ -520,8 +519,7 @@ class Keyring(): # output of --sign-key command = self.context.build_command([['sign-key', 'lsign-key'][local], pattern]) - if self.context.debug: - print('command:', command, file=self.context.debug) + logger.debug('command: %s', command) proc = subprocess.Popen(command, # nosec stdin=subprocess.PIPE, stdout=subprocess.PIPE, @@ -624,7 +622,7 @@ class TempKeyring(Keyring): Keyring.__init__(self, tempfile.mkdtemp(prefix="pygpg-")) def __del__(self): - shutil.rmtree(self.homedir) + shutil.rmtree(self.homedir, ignore_errors=True) class OpenPGPkey(): """An OpenPGP key. @@ -841,7 +839,7 @@ class OpenPGPkey(): def __repr__(self): - s = '<OpenPGPKey(%s UIDs:%d)>' + s = '<OpenPGPkey(%s UIDs:%d)>' s %= (self.fpr, len(self.uidslist)) return s @@ -863,6 +861,25 @@ class OpenPGPkey(): if i == 4: s += ' ' return s + def __eq__(self, other): + """ + Two keys are equal if their fingerprint matches. If either don't + have a fingerprint, we can't say for sure that they're equal + """ + if isinstance(other, self.__class__): + return (self.fpr and + self.fpr and other.fpr + and self.fpr == other.fpr) + else: + return NotImplemented + + def __neq__(self, other): + if isinstance(other, self.__class__): + return not self.__eq__(other) + else: + return NotImplemented + + class OpenPGPuid(): def __init__(self, uid, trust, creation = 0, expire = None, uidhash = ''): self.uid = uid diff --git a/monkeysign/gtkui.py b/monkeysign/gtkui.py index e497666b7a05980a57dfc1a7e57a84875b05481f..1fda3fe47bceee3f675db575c9b44ef71478ec44 100644 --- a/monkeysign/gtkui.py +++ b/monkeysign/gtkui.py @@ -28,6 +28,8 @@ import io import stat import subprocess # nosec import webbrowser +import logging +import warnings from glib import GError import gobject @@ -46,6 +48,8 @@ import monkeysign.translation from monkeysign.msg_exception import errorhandler import monkeysign +logger = logging.getLogger(__name__) + class MonkeysignScanUi(MonkeysignUi): """sign a key in a safe fashion using a webcam to scan for qr-codes @@ -90,6 +94,10 @@ passwords. self.window = MonkeysignScan() self.window.msui = self + # Add a handler to the root logger that displays warnings and + # errors as dialogs + logging.getLogger().addHandler(GTKLoggingHandler(self.window)) + # XXX: this probably belongs lower in the stack, # because we don't want to create a temporary keyring # just when we start the graphical UI, but instead @@ -131,12 +139,14 @@ passwords. self.window.resume_capture() def warn(self, prompt): - """display the message but let things go""" - md = gtk.MessageDialog(self.window, gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, prompt) - with gtk.gdk.lock: - md.run() - md.destroy() + """display the message but let things go + + DEPRECATED: This method has been deprecated. Use Logger.warning instead. + """ + warning = ("This method is deprecated, and will be removed in a future version. " + "As alternative, use Logger.warning()") + warnings.warn(warning, DeprecationWarning) + logger.warning(prompt) def choose_uid(self, prompt, key): md = gtk.Dialog(prompt, self.window, gtk.DIALOG_DESTROY_WITH_PARENT, @@ -161,11 +171,11 @@ passwords. label = None if response == gtk.RESPONSE_ACCEPT: - self.log(_('okay, signing')) + logger.info(_('okay, signing')) label = [radio for radio in self.uid_radios.get_group() if radio.get_active()][0].get_label() else: - self.log(_('user denied signature')) + logger.info(_('user denied signature')) md.destroy() return label @@ -234,7 +244,7 @@ class MonkeysignScan(gtk.Window): except GError: # misconfigured, ignore # XXX: no access to logging, again - # self.msui.warn("could not find icon: %s" % e) + # logger.warning("could not find icon: %s", e) pass except pkg_resources.DistributionNotFound: # not installed system-wide, ignore @@ -363,6 +373,8 @@ class MonkeysignScan(gtk.Window): self.qrcodewidget.pack_start(label, False) self.qrcodewidget.pack_start(swin) + self.qrcodewidget.connect("event", self.qr_code_event) + def create_secret_keys_display(self): """list the secret keys for selection somewhere""" i = 0 @@ -469,9 +481,15 @@ class MonkeysignScan(gtk.Window): if not verified: raise GpgRuntimeError(0, _('cannot find signature for image file')) except GpgRuntimeError : - self.msui.warn(_("The image provided cannot be verified using a trusted OpenPGP signature.\n\nMake sure the image comes from a trusted source (e.g. your own camera, which you have never left unsurveilled) before signing this!\n\nDO NOT SIGN UNTRUSTED FINGERPRINTS!\n\nTo get rid of this warning, if you really trust this image, use the following command to sign the file\n\n gpg -s --detach %s\n") % filename) + logger.warning(_("The image provided cannot be verified using a trusted OpenPGP signature.\n\n" + "Make sure the image comes from a trusted source (e.g. your own camera, which " + "you have never left unsurveilled) before signing this!\n\nDO NOT SIGN UNTRUSTED " + "FINGERPRINTS!\n\n" + "To get rid of this warning, if you really trust this image, use the following " + "command to sign the file\n\n" + " gpg -s --detach %s\n"), filename) else: - self.msui.log(_('image signature verified successfully')) + logger.info(_('image signature verified successfully')) self.scan_image(filename) return @@ -513,7 +531,7 @@ class MonkeysignScan(gtk.Window): self.process_scan(symbol.data) found = True if not found: - self.msui.warn(_('no data found in image!')) + logger.warning(_('no data found in image!')) def save_qrcode(self, widget=None): """Use a file chooser dialog to enable user to save the current QR @@ -521,7 +539,7 @@ class MonkeysignScan(gtk.Window): if self.active_key is None: # XXX: without this, warn() freezes, go figure gtk.gdk.threads_leave() - self.msui.warn(_('No identity selected. Select one from the identiy menu or generate a OpenPGP key if none is available.')) + logger.warning(_('No identity selected. Select one from the identiy menu or generate a OpenPGP key if none is available.')) return key = self.active_key image = self.make_qrcode(key.fpr) @@ -547,7 +565,7 @@ class MonkeysignScan(gtk.Window): if self.active_key is None: # XXX: without this, warn() freezes, go figure gtk.gdk.threads_leave() - self.msui.warn(_('No identity selected. Select one from the identiy menu or generate a OpenPGP key if none is available.')) + logger.warning(_('No identity selected. Select one from the identiy menu or generate a OpenPGP key if none is available.')) return keyid = self.active_key.subkeys[0].keyid() print_op = gtk.PrintOperation() @@ -647,7 +665,7 @@ class MonkeysignScan(gtk.Window): # this is actually because the key was # imported without having to create a dialog pass - self.msui.log(_('fetching finished')) + logger.info(_('fetching finished')) if condition == 0: # 2. copy the signing key secrets into the keyring self.msui.copy_secrets() @@ -697,7 +715,7 @@ class MonkeysignScan(gtk.Window): def process_scan(self, data): """process zbar-scanned data""" - self.msui.log(_('zbar captured a frame, looking for 40 character hexadecimal fingerprint')) + logger.info(_('zbar captured a frame, looking for 40 character hexadecimal fingerprint in %s'), data) m = re.search("((?:[0-9A-F]{4}\s*){10})", data, re.IGNORECASE) if m is not None: @@ -709,8 +727,8 @@ class MonkeysignScan(gtk.Window): # interactive but that's ugly as hell - find_key() should # take a callback maybe? # 1.a) from the local keyring - self.msui.log(_('looking for key %s in your keyring') - % self.msui.pattern) + logger.info(_('looking for key %s in your keyring'), + self.msui.pattern) self.msui.keyring.context.set_option('export-options', 'export-minimal') if self.msui.tmpkeyring.import_data(self.msui.keyring.export_data(self.msui.pattern)): @@ -728,7 +746,7 @@ class MonkeysignScan(gtk.Window): if self.msui.options.keyserver is not None: self.msui.tmpkeyring.context.set_option('keyserver', self.msui.options.keyserver) command = self.msui.tmpkeyring.context.build_command(['recv-keys', self.msui.pattern]) - self.msui.log('cmd: ' + str(command)) + logger.info('cmd: ' + str(command)) self.dialog = gtk.Dialog(title=_('Please wait'), parent=None, flags=gtk.DIALOG_MODAL, buttons=None) self.dialog.add_button('gtk-cancel', gtk.RESPONSE_CANCEL) message = gtk.Label(_('Retrieving public key from server...')) @@ -748,7 +766,7 @@ class MonkeysignScan(gtk.Window): if self.dialog.run() == gtk.RESPONSE_CANCEL: proc.kill() else: - self.msui.warn(_('data found in barcode does not match a OpenPGP fingerprint pattern: %s') % data) + logger.warning(_('data found in barcode does not match a OpenPGP fingerprint pattern: %s'), data) self.resume_capture() def resume_capture(self): @@ -791,3 +809,47 @@ class MonkeysignScan(gtk.Window): def documentation_dialog(self, widget, data=None): webbrowser.open(monkeysign.__documentation__, autoraise=True) + + def qr_code_event(self, thing, event): + if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3: + self.qr_code_right_click_menu(event) + + def qr_code_right_click_menu(self, event): + menu = gtk.Menu() + menu_items = [ + (_('_Save QR code as...'), self.save_qrcode), + (_('_Print QR code...'), self.print_op), + ] + + for item in menu_items: + new_menu_item = gtk.MenuItem(item[0]) + new_menu_item.connect('activate', item[1]) + new_menu_item.show() + menu.append(new_menu_item) + + menu.popup(None, None, None, event.button, event.time) + + +class GTKLoggingHandler(logging.Handler): + """ + Handles log messages and displays a dialog with the message. + """ + def __init__(self, window): + self.window = window + super(GTKLoggingHandler, self).__init__() + + def emit(self, record): + # Set the dialog type for ERROR, CRRITICAL, and WARNING. Don't + # show any other levels. + if record.levelno is logging.ERROR or record.levelno is logging.CRITICAL: + level = gtk.MESSAGE_ERROR + elif record.levelno is logging.WARNING: + level = gtk.MESSAGE_WARNING + else: + return + + md = gtk.MessageDialog(self.window, gtk.DIALOG_DESTROY_WITH_PARENT, + level, gtk.BUTTONS_OK, record.msg) + with gtk.gdk.lock: + md.run() + md.destroy() diff --git a/monkeysign/tests/files/7B75921E.asc b/monkeysign/tests/files/7B75921E.asc index 78e8091241ca18374c9b0a4d310b92b6ad04264c..69e1744aa21da63d979b91a3d3155048be64be8e 100644 --- a/monkeysign/tests/files/7B75921E.asc +++ b/monkeysign/tests/files/7B75921E.asc @@ -1,5 +1,4 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1 mQINBEogKJ4BEADHRk8dXcT3VmnEZQQdiAaNw8pmnoRG2QkoAvv42q9Ua+DRVe/y AEUd03EOXbMJl++YKWpVuzSFr7IlZ+/lJHOCqDeSsBD6LKBSx/7uH2EOIDizGwfZ @@ -12,168 +11,208 @@ V628Tn9+8oDg6c+dO3RCCmw+nUUPjeGU0k19S6fNIbNPRlElS31QGL4H0IazZqnE q1wWFFQDskG+ybN2Qy7SZMQtjjOqM+CmdeAnQGVwxowSDPbHfFpYeCEb+Wzya337 Jy9yJwkfa+V7e7Lkv9/OysEsV4hJrOh8YXu9a4qBWZvZHnIO7zRbz7cqVBKmdrL2 iGqpEUv/x5onjNQwpjSVX5S+ZRBZTzah0w186IpXVxsU8dSk0yeQskblrwARAQAB -tDhBbnRvaW5lIEJlYXVwcsOpIChob21lIGFkZHJlc3MpIDxhbmFyY2F0QGFuYXJj -YXQuYXRoLmN4PokCNgQwAQgAIAUCU85w3RkdIHJlbW92aW5nIGNvbW1lbnQgZmll -bGRzAAoJEHkhUlJ7dZIeuvsQALv5rpGEI39KvmQHPrW8Y8ycN+03b1EeCTsGo/OS -8wHhj8EmCno2HXVPVjauU4dpusEzvQHsiKqIkpknq0heA/oTkUxSrBLz8hRrmL3X -N87StNBOVFNkqAgAr2eoIdi2xpm3TAMqsUUj6jjM4K2JOjduIPSvcpfg43vrAo/Y -54W4rINbhTOyCjRjQkqUhPL7bvVJvAlmpluKSDdS+ON5xEWR38g3loGkCZQvjBdS -B4hhvaxp49MGanVTwIHzI9RSrb+UtYHM3H0G5a4+AgiVYGuwqIJZc15hI3Vz+cxP -oFJ2haetoKT9rTwnqxZxknW+JnldH2V7KuyEMvWs5Jo3i8qSFfLCwG1jW3LGuILD -BNtc+QiMxy7NdOZpP3Lex9bqQ6p7io6FfNK7RN/kbeUyQNvIzLu6RpB0EkMmI2XD -talZcOZ1TUmQ4gP941HQBBjp/uDAUlkoa4/HIFxRwBTDnPspkG19HLub6QDs5/AB -3/55CGS9pBHrU2EsPQ9cLwzb+zfQmJi2vC2IzcVrbwVcTRpAluHo8kUVlgTHpnbw -XOHrr40FRuKgex7TREBK1OyAn1gYdQUFVhau+SjdcAz9zEVI8aj23Umu4oTVYVOj -cx2flzZCcdzyG6nzd3JQVWm3gpK3TgWo8eC/hNa7s5aIs7ThTofGXh+d5bUtcZx+ -FbJ5tCVBbnRvaW5lIEJlYXVwcsOpIDxhbmFyY2F0QGRlYmlhbi5vcmc+iQI9BBMB -CAAnAhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheABQJXPkWABQkPEHO3AAoJEHkh -UlJ7dZIegzsQALvO3xo2xx84VdZ0Kc1tU9SlLaAZFZttbOvALD4o3x55pyUEaqWH -4huDRcIRkhFq9FQITT7hj+dXkofR1MSdoUyuS/+XMYTOKBJNFUKT4JcfDr7pa8EV -sXWpxw/3gaivgi8+fo4niKFCDD0NdTO9c/19QU3Wa/11VxFrZvGS4jGb2eae8stg -2QGPIB6uobevypXbGNGe9TQ/TILZOlPVLyznf+Tj+9g0iU0oWYCVvj0z3Hrf3w1E -QX4jx2GSC8KDSM1pdajRkON8qGQgud8URKoqGQRYjHadtpbSY38h++s/NSmWDTPJ -KRJd4J2VDaYNtH0sQYVhumv+K48DRGQDcc0AHbj2f6NtzCfLLObBPrP0hgn1laPb -ujyqv/vUVKZCke5SEHDJN+eUSYv1rO1lv+1X4yugle+DyP2Pinls7jxR74L42ST0 -NM33OamQacrMtKtZi3Ql0+x5lkcG0/9TEVlIyc2gZEiFL/9V4XWDbW0Of39vniCh -IYcxeQGL+369UNr7a3MXE/Z5MPpqVM6KuyPvhWfexwJyvS5CFcb5VX+awx67jodQ -1PxM6pIESJdfzv7lSwWRuhIzSG4WtfISpzywdrrjOdn9D6BdbY9mVvoUE1lrD3XY -fDzU8aIveHFcLQ1iqqZMecosqbM0bi2W9zHb36uE5jKNN8qxXyRTMOM7tC5BbnRv -aW5lIEJlYXVwcsOpIChEZWJpYW4pIDxhbmFyY2F0QGRlYmlhbi5vcmc+iQI2BDAB -CAAgBQJTznDdGR0gcmVtb3ZpbmcgY29tbWVudCBmaWVsZHMACgkQeSFSUnt1kh5c -RA/9FewI0auM0dynulECk2aLV+r1bbFmbLyutBwKIajLWlMc6kOLHHa8FS2fVb+2 -xx1iIGLz7Naf6uvj7ZCoiRFQit9Erl76rAcDRt/5gcm8SpVlTX7K2E0obNn45V7O -CVaxa8IbITf7gbFImhsIufDBMuX1RWe1jEzCeon2hy2yU0DNz3IMGGEfvtFhSlH+ -6ZRG/9Qfa6zORi79089ny/kXJ/HJj6xvPi6foXccCAwPwQTALcpfT4Ti8YFmQqOz -FssNYLz3IC0I4w8ShqKuFHEU8XnMGePHG+MstJx4uRm6yQA/F7t5Ie5zwOE5hWOW -SDjuSnUuZW8g7zz1liWZDLGgRjs8Wu/l+q7W4tR3IgcnO1IcA7F+lvQezbamuzeJ -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 -v0PIz18nn90Xm9tI5v73MPrU2/uv -=5gjM +tCpBbnRvaW5lIEJlYXVwcsOpIDxhbmFyY2F0QG9yYW5nZXNlZWRzLm9yZz6JAlQE +EwEIAD4CGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AWIQSNyQHOZBRsBIrVD7t5 +IVJSe3WSHgUCWs1oyAUJEtb2KAAKCRB5IVJSe3WSHh+DEACzlorp/RzyaI2QPOgx +xqUBIiLK6V2KEEjDpTWe7VUWZpe7i50otpbxFTfHqz0dh7LFsgUyj2VybpOk759o +xKpZ/wRJx6+G47NLW1PEV3NfBJDhxQvt5DCcUjRYcgSkqCgfQzK9ZOqqsZKXX5vg +I6p+4G17y64jvxFTW+wnHjyDOw1nzOwlLRGtHXOScVzKrZycZ/GUH6z6IjywxK5S +YZI0hUw5JO2HL4tjE6TA4dZsrq4URVmJnrw8Y1rg/dqeMU4iPOaD/UNtQ5bcMSKW +PnVkD+F8K6OoiUVCsGYLGFfVweEJ5KtCNJhGRj1D17uhC3QX7oxhTE6Czf1DYNPN +zbQpsgLipo43QU806muhUbaYnpqFl5D/IWZDiG2Jmx6SH+4A1B2JiIc2j0K8+jwf +QOmzLSlOIdpGfDgEReTno2FXSal3+r1HHAnMHPxTzfJFGYcJazZ07buosbHhpcd0 +Exx3yi1cbJE8Y/dREezNH5jwovM+6vGbZWHEJ8wN+ZeB9zhLybwa6CnyXLU8dnFG +3ZQ9SW0mgo0f4a1MabLJk0ljLyBom+DdzAt+yRQfnbTnraM9XZS6zDVY5Uq6YuK6 +EtCQvx6q8obypGYApJRSs04/gM8QLTLyuv7b18f+OltYPzJcclZ1u/gOm3RJm8Wn +fYdUMMTnoifq4efwQUNopKnRq7QjQW50b2luZSBCZWF1cHLDqSA8YW5hcmNhdEBh +bmFyYy5hdD6JAlQEEwEIAD4CGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AWIQSN +yQHOZBRsBIrVD7t5IVJSe3WSHgUCWs1oxgUJEtb2KAAKCRB5IVJSe3WSHqSvD/oC +QsESsCqFwM1bcMh0fB+mGzNoMEVPzqwzDqmBedzTD4LD5GL0fJFFy9D2bR3SXTUH +U3PCdrUHcZGa5VMIKSC75LRJE0fXcJYqfIydLnCIPV9dCAsgAjOF7lvpDblAj7Nz +60lYnK0l+4gMqKUmaLnkBeFWgLPh8ElI2ANZ+KBpwZp25VoufQnqQjNcgCTyyEI7 +7P6qtiLs9nDqbGoxAMgrJJTYI/4qzvGvD8XCjebu04lpguyCgfOdFEovXCIu8IOF +43UROZz0pI06CsEuXozH6Zvy2dLUOAXqQafPnKv0995abNZtCnNq5MAqeAVZ1qv3 +ur3v8Hr5efC/eAPY0BfyOJzKi/u2pfoVw7uRI8G+7BG6OdPXCI/YvkKc3v50Pvmp +t7Q8QrNpJnl9cMHb6t0Cg7Ux8pmEp/wclc991Lk4X1dtweMYIc+y9iuDqpjtgdqO +VqnQyBcfPJAxSyawLE/gzc6NXSRSiOOnrVSW4PH1ewej1+GPYgKstbP9iASyfVbU +++b+34aw3cIQkW5ejmmocb52XL7ViL//0Bf8aCfpeohRf+t9W1Io6litIpwKFV0o +60LPAiC1eW8oXzx5STo0pt+5NJLx5IaSjTTO3fyAfRzmAhgffHrBnDliafjhPr5C +tFp9p1UIhQtEtZ3Elz8om54DsZql3cN9W1t/E7TORbQmQW50b2luZSBCZWF1cHLD +qSA8YW5hcmNhdEBrb3VtYml0Lm9yZz6JAlQEEwEIAD4CGwMFCwkIBwMFFQoJCAsF +FgIDAQACHgECF4AWIQSNyQHOZBRsBIrVD7t5IVJSe3WSHgUCWs1oyAUJEtb2KAAK +CRB5IVJSe3WSHjbDD/4zquw89EKLivl3yBkHecvHPAz4qceOSkxjw7fWFu6ueTAu +/u2AWf6YJNAeTVhK7c8UD9NDtnIZNhGePIheUFuKTvSeGWCAYH/ruCkNhp4pI67a +aLXVbcJACp8xZh9vWNZM6pxo3/6krS5r4qdsXDFoEzzR2VozWQ+7xJiLLMIB50Ir +OeTZXZXwf6qrwBfuCwALSWOoYxrCbsSf9CrZCihmrffjTTVpj7RoVZQAdcVkElC0 +iXVIIRWUbnm1UlvXeoyt3XGDKO1zfHHc4g0OhPaZ5K9ajidHT9tKX/ND/g5Ys8w+ +8sFsankmc/m8xwOMQqltAgAnoVn7V7Zi0l0SE4fxC+ASte1NcH09d+tbIrh9xq/d +0SShpaGuBybEEPKtbp9hB7E1C2qIqBtOcV7v8pAq/3T2U3KI+XUKCzdUhtAiscwC +waZKHbBNbh8tRBT2ERlpqJWXKqM8xJSsCM6npkckc21DQjyz0KLWXz7Y7NIWCCMH +0LRlMCBLbWa139sxfwPciWp5H26b6Uflo3WQ1XZgLGTbH23qubHPBDigpj3uv+CK +TS+OHCNckvAk5VGtDCnHX+Ne6xxCEjwJ9D3BVIuS1bJ4HpEW1np5Ct41jENYjNLr +5iNuMi5szW2zqHPVOJhgaCJNcbGl6nyVCgSHjDbT9RKS14hlMSyfQOFMbLFAnLQl +QW50b2luZSBCZWF1cHLDqSA8YW5hcmNhdEBkZWJpYW4ub3JnPokCVAQTAQgAPgIb +AwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgBYhBI3JAc5kFGwEitUPu3khUlJ7dZIe +BQJazWjIBQkS1vYoAAoJEHkhUlJ7dZIe3IUP/3G/keDpoV5OwBct1K3TLNMAZSIC +cy4Nh+NT6/XQZlsT2FtSZn3zESsw9IaHE/4nUJOW2C6WcJo85h/obDsnsEGl9KfC +t84jXMeJZQg3o3O26dRLDNZQVSO8iliNzHX6/V8NYtWulZ/x9Hqthhg8HcM9Tor7 +uKuQbNSE5M8SzsNH4cb9aSeKeIqMoOY2OS41eTS4uHyaogCBRpnnj+AAhuv7eUeU +wzrfkQkzPtq/2y0O6L7Ce8K9u0BPL4ywBFe6zqBafeevTo1kCCLf+95Af42nl/bW +lbAyCnFPegEkPWqj74wSqFQMHrkYx+er2FykPoI0WYaunq1LZlolk/v95+U5WsNr +f7uwz7UmyDKADM69x7DTFUEZ1PoExPM1Zo+w5RTXFqfWR5uroKJhw5UkGhYrqg1T +RSeqbB14DLWnQFZYztdVgTDqDM5g0PJpaA1+COMH5PpyhdRg1UfWET32LZDpbnqx +6ntiq/AfHQeHp+Ibugu/PO/qD8T+kAs3GVXDzJd+rS8quxLekkKiiQp1S5ZIzCsI +Tp2fVOqIgTszjlVy/ypGUkLnbDQE/tu22faaksdd6jpzgbupbZUOPSPaywUUVOEA +jb+EwZPFQWIAzbbTflGY8L10leez1X0HYfcC95hRSEobdBlK9iWtS/7grN/o85RT +iuuQgoul178m+VnotC1BbnRvaW5lIEJlYXVwcsOpICh3b3JrKSA8YW5hcmNhdEBr +b3VtYml0Lm9yZz6JAjYEMAEIACAFAlPOcNsZHSByZW1vdmluZyBjb21tZW50IGZp +ZWxkcwAKCRB5IVJSe3WSHvC/D/sH8ak9X0dom7HTDWyDb9fO4g95jP4MOOGuTL2I +P7SPn3OoXZtAVaHihgvp+6H7Z0C4S+JiNL8XagcZmv7xZ6cbXyfCWAU6JEd6rTDo +ZUYC8KJ69eExBZOp2AQMPEM4H3tZ4MV635k1ahwW4aLWXzbyWCzkFBLSBpeOoLn5 +5aa1aQhzlmhCjQhTh158AUlEiCqCB2DllQfCJ0Q5C3dpzIWkDWoMZ3Hgw9Yg+rrL +p2oFRkijmRFoYmBB9hoP/LgLzhXZCQujhFBmL7FHSWxG07V98PEJK9NZ/xVLf+zw +J4IDIHI0hrBDkS1Gd82lp7UK7kICZ9ognB2L8m3ObACzg1+9cOsqRLiedjsvGTxT +sARpgFbzRhB97fuudZG1pK0PWqexIWzsmMzNlm/q+aCj+rYZVg6L+gnIs85bHqh5 +vhW71SfhbljYJBJVNcxJF+2pOtaE71TqvNbICK4UIiCubUtts9ydL/fMHmpternc +ftxzqT0rSWI3rhywRb6ZiY9OVrbIQ+A0UPcJf5yozEpLyK57eK3U5MNMvtuI5JKs +On1eZOV30df+70mWVgniTpL4m6Qb5kEVDhFRjk6X2PW2CzwCLGQvfaNI6NwHB0bT +Dpxhva+pSKyTzwKn7w8L026QGs1NAufaNTZRbPiBSgJ3QIkSR/zN5ubzmoJLovGk +GdAGNLQuQW50b2luZSBCZWF1cHLDqSAoRGViaWFuKSA8YW5hcmNhdEBkZWJpYW4u +b3JnPokCNgQwAQgAIAUCU85w3RkdIHJlbW92aW5nIGNvbW1lbnQgZmllbGRzAAoJ +EHkhUlJ7dZIeXEQP/RXsCNGrjNHcp7pRApNmi1fq9W2xZmy8rrQcCiGoy1pTHOpD +ixx2vBUtn1W/tscdYiBi8+zWn+rr4+2QqIkRUIrfRK5e+qwHA0bf+YHJvEqVZU1+ +ythNKGzZ+OVezglWsWvCGyE3+4GxSJobCLnwwTLl9UVntYxMwnqJ9octslNAzc9y +DBhhH77RYUpR/umURv/UH2uszkYu/dPPZ8v5FyfxyY+sbz4un6F3HAgMD8EEwC3K +X0+E4vGBZkKjsxbLDWC89yAtCOMPEoairhRxFPF5zBnjxxvjLLSceLkZuskAPxe7 +eSHuc8DhOYVjlkg47kp1LmVvIO889ZYlmQyxoEY7PFrv5fqu1uLUdyIHJztSHAOx +fpb0Hs22prs3iXHIFZXEaifzh3GCXgUrcyrpI8ZITt7bSwHUliHqT2B3OcPASQip +XWMBBU9wXRBGuHTtOv4HHB7TVblNr4PEbfEJeqttQpQxGK3hrP7jx4XJk17H8VuN +Iv75+sGZxAVdumOe5a1YFHlShs12t5BLlEzDomDgg0cVQNeTRwPy3zcJ/zNEA8cr +7bSspkjPBo5Oy9EcLlhOjbI6gUuEmFU0QrfzVrrE2k837FpkxxEYlal8/0hsCOCf +/mJ9K+0WQnc40c002GCRXQbEBc22XhQX1Ongiz7aHsTNHpVzb7TT2mz11KMCtDhB +bnRvaW5lIEJlYXVwcsOpIChob21lIGFkZHJlc3MpIDxhbmFyY2F0QGFuYXJjYXQu +YXRoLmN4PokCNgQwAQgAIAUCU85w3RkdIHJlbW92aW5nIGNvbW1lbnQgZmllbGRz +AAoJEHkhUlJ7dZIeuvsQALv5rpGEI39KvmQHPrW8Y8ycN+03b1EeCTsGo/OS8wHh +j8EmCno2HXVPVjauU4dpusEzvQHsiKqIkpknq0heA/oTkUxSrBLz8hRrmL3XN87S +tNBOVFNkqAgAr2eoIdi2xpm3TAMqsUUj6jjM4K2JOjduIPSvcpfg43vrAo/Y54W4 +rINbhTOyCjRjQkqUhPL7bvVJvAlmpluKSDdS+ON5xEWR38g3loGkCZQvjBdSB4hh +vaxp49MGanVTwIHzI9RSrb+UtYHM3H0G5a4+AgiVYGuwqIJZc15hI3Vz+cxPoFJ2 +haetoKT9rTwnqxZxknW+JnldH2V7KuyEMvWs5Jo3i8qSFfLCwG1jW3LGuILDBNtc ++QiMxy7NdOZpP3Lex9bqQ6p7io6FfNK7RN/kbeUyQNvIzLu6RpB0EkMmI2XDtalZ +cOZ1TUmQ4gP941HQBBjp/uDAUlkoa4/HIFxRwBTDnPspkG19HLub6QDs5/AB3/55 +CGS9pBHrU2EsPQ9cLwzb+zfQmJi2vC2IzcVrbwVcTRpAluHo8kUVlgTHpnbwXOHr +r40FRuKgex7TREBK1OyAn1gYdQUFVhau+SjdcAz9zEVI8aj23Umu4oTVYVOjcx2f +lzZCcdzyG6nzd3JQVWm3gpK3TgWo8eC/hNa7s5aIs7ThTofGXh+d5bUtcZx+FbJ5 +uQENBFAGwRgBCADTtdA/YZOdYY35bKWKokkHkXTklnwWKbAMWbcgGaaDbPEMl+0w +Am75WoBRUF/ZetwbQQ1SlNsbqymeFp2LiwbwU3xFmw7v/TAJrYJxIPEV8fjApIIa +o7PWzz0o8na+Ocz6w2qKWc1CJkryLT/t/JcUnPsFzlp/nYkOyrS0BqdkNwj9/hSO +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 +=2U/l -----END PGP PUBLIC KEY BLOCK----- diff --git a/monkeysign/tests/test_gpg.py b/monkeysign/tests/test_gpg.py index 03183f70e1cefed9d5b2942abc08a00bc2d54084..b099fc3fe435b6fbe229b1736856a1f87ff6a622 100755 --- a/monkeysign/tests/test_gpg.py +++ b/monkeysign/tests/test_gpg.py @@ -23,10 +23,11 @@ Tests that require network access should go in test_network.py. from __future__ import print_function import sys, os, shutil -import io +from io import StringIO import unittest import tempfile import re +import logging # monkeypatch 2.7 unittest to support assertRegex and assertCountEqual try: @@ -49,6 +50,8 @@ sys.path.insert(0, os.path.dirname(__file__) + '/..') from monkeysign.gpg import * from test_lib import find_test_file, skipUnlessUnicodeLocale, skipIfDatePassed +logger = logging.getLogger(__name__) + class TestContext(unittest.TestCase): """Tests for the Context class. @@ -59,7 +62,7 @@ class TestContext(unittest.TestCase): options = Context.options # ... and this is the rendered version of the above - rendered_options = ['gpg', '--command-fd', '0', '--with-fingerprint', '--list-options', 'show-sig-subpackets,show-uid-validity,show-unusable-uids,show-unusable-subkeys,show-keyring,show-sig-expire', '--batch', '--fixed-list-mode', '--no-tty', '--with-colons', '--use-agent', '--status-fd', '2', '--quiet' ] + rendered_options = ['gpg', '--command-fd', '0', '--with-fingerprint', '--list-options', 'show-sig-subpackets,show-uid-validity,show-unusable-uids,show-unusable-subkeys,show-keyring,show-sig-expire', '--batch', '--fixed-list-mode', '--no-tty', '--with-colons', '--use-agent', '--status-fd', '2', '--quiet', '--no-verbose' ] def setUp(self): self.gpg = Context() @@ -94,16 +97,6 @@ class TestContext(unittest.TestCase): """make sure version() returns something""" self.assertTrue(self.gpg.version()) - def test_seek_debug(self): - """test if seek actually respects debug""" - self.gpg.debug = True # should yield an attribute error, that's fine - with self.assertRaises(AttributeError): - self.gpg.seek(io.BytesIO(b'test'), 'test') - # now within a keyring? - k = TempKeyring() - k.context.debug = True - with self.assertRaises(AttributeError): - k.import_data(open(find_test_file('96F47C6A.asc')).read()) class TestTempKeyring(unittest.TestCase): """Test the TempKeyring class.""" @@ -229,9 +222,8 @@ class TestKeyringWithKeys(TestKeyringBase): @todo we should check the data structure """ - # just a cute display for now - for fpr, key in list(self.gpg.get_keys('96F47C6A').items()): - print(key) + for fpr, key in self.gpg.get_keys('96F47C6A').items(): + logger.debug(key) def test_sign_key_wrong_user(self): """make sure sign_key with a erroneous local-user fails @@ -241,14 +233,14 @@ class TestKeyringWithKeys(TestKeyringBase): with self.assertRaises(GpgRuntimeError): self.gpg.sign_key('7B75921E', True) - @skipIfDatePassed('2017-06-01T00:00:00UTC') + @skipIfDatePassed('2019-06-05T00:00:00UTC') def test_sign_key_all_uids(self): """test signature of all uids of a key""" self.assertTrue(self.gpg.sign_key('7B75921E', True)) self.gpg.context.call_command(['list-sigs', '7B75921E']) self.assertRegex(self.gpg.context.stdout, 'sig:::1:86E4E70A96F47C6A:[^:]*::::Second Test Key <unittests@monkeysphere.info>:10x:') - @skipIfDatePassed('2017-06-01T00:00:00UTC') + @skipIfDatePassed('2019-06-05T00:00:00UTC') def test_sign_key_single_uid(self): """test signing a key with a single uid""" self.assertTrue(self.gpg.import_data(open(find_test_file('323F39BD.asc')).read())) @@ -257,19 +249,21 @@ class TestKeyringWithKeys(TestKeyringBase): self.assertRegex(self.gpg.context.stdout, 'sig:::1:A31E75E4323F39BD:[^:]*::::Monkeysphere second test key <bar@example.com>:[0-9]*x:') @skipUnlessUnicodeLocale() + @skipIfDatePassed('2019-06-05T00:00:00UTC') def test_sign_key_one_uid(self): """test signature of a single uid""" self.assertTrue(self.gpg.sign_key('Antoine Beaupré <anarcat@debian.org>')) self.gpg.context.call_command(['list-sigs', '7B75921E']) self.assertRegex(self.gpg.context.stdout, 'sig:::1:86E4E70A96F47C6A:[^:]*::::Second Test Key <unittests@monkeysphere.info>:10x:') - @skipIfDatePassed('2017-06-01T00:00:00UTC') + @skipIfDatePassed('2019-06-05T00:00:00UTC') def test_sign_key_as_user(self): """normal signature with a signing user specified""" self.gpg.context.set_option('local-user', '96F47C6A') self.assertTrue(self.gpg.sign_key('7B75921E', True)) @skipUnlessUnicodeLocale() + @skipIfDatePassed('2019-06-05T00:00:00UTC') def test_sign_already_signed(self): """test if signing a already signed key fails with a meaningful message""" self.assertTrue(self.gpg.sign_key('Antoine Beaupré <anarcat@debian.org>')) @@ -439,8 +433,9 @@ fpr:::::::::C9E1F1230DBE47D57BAB3C60586073B34023702F: uid:::::::2451063FCBB4D262938687C2D8F6B949B0A3AF01::The Anarcat <anarcat@anarcat.ath.cx>: ssb::2048:16:C016FF12EB8D47BB:1110320966::::::::::""") - def test_print(self): - print(self.key) + def test_str(self): + """Tests that the __str__ call of OpenPGPKey works for secret keys""" + self.assertIn('C9E1 F123 0DBE 47D5 7BAB 3C60 5860 73B3 4023 702F', self.key.__str__()) if __name__ == '__main__': unittest.main() diff --git a/monkeysign/tests/test_lib.py b/monkeysign/tests/test_lib.py index 6bf21f99f85893775f80bc97995b40b1b2b57e54..d8b23baffab2279958b50a184a3e7e85d4df9b16 100755 --- a/monkeysign/tests/test_lib.py +++ b/monkeysign/tests/test_lib.py @@ -92,5 +92,39 @@ def skipIfDatePassed(date, fmt='%Y-%m-%dT%H:%M:%S%Z'): return lambda func: func +def skipUnlessNetwork(): + """add a knob to disable network tests + + to disable network tests, use PYTEST_USENETWORK=no. by default, it + is assumed there is network access. + + this is mainly to deal with Debian packages that are built in + network-less chroots. unfortunately, there is no standard + environment in dpkg-buildpackage or ./debian/rules binary that we + can rely on to disable tests, so we revert to a custom variable + that can hopefully make it up to the pybuild toolchain + + I looked at DEB_BUILD_OPTIONS=network, but that is not standard + and only mentionned once here: + + https://lists.debian.org/debian-devel/2009/09/msg00992.html + + DEB_BUILD_OPTIONS is also not set by default, so it's not a good + way to detect Debian package builds + + pbuilder uses USENETWORK=no/yes, schroot uses UNSHARE_NET, but + those are not standard either, see: + + https://github.com/spotify/dh-virtualenv/issues/77 + https://github.com/codelibre-net/schroot/blob/2e3d015a759d2b5106e851af34c8d5974d84f18e/lib/schroot/chroot/facet/unshare.cc + """ + + if ('PYTEST_USENETWORK' in os.environ + and 'no' in os.environ.get('PYTEST_USENETWORK', '')): + return unittest.skip('network tests disabled (PYTEST_USENETWORK=no)') + else: + return lambda func: func + + if __name__ == '__main__': unittest.main() diff --git a/monkeysign/tests/test_network.py b/monkeysign/tests/test_network.py index 6e330829cf2fcfad27a04f94e98c3fa19b7520dc..b7f8d1fa951cb0b56ab70d6d816ff95e87d65774 100755 --- a/monkeysign/tests/test_network.py +++ b/monkeysign/tests/test_network.py @@ -29,42 +29,7 @@ import sys sys.path.insert(0, os.path.dirname(__file__) + '/../..') from monkeysign.gpg import TempKeyring -from test_lib import TestTimeLimit, AlarmException, find_test_file -import test_ui - - -def skipUnlessNetwork(): - """add a knob to disable network tests - - to disable network tests, use PYTEST_USENETWORK=no. by default, it - is assumed there is network access. - - this is mainly to deal with Debian packages that are built in - network-less chroots. unfortunately, there is no standard - environment in dpkg-buildpackage or ./debian/rules binary that we - can rely on to disable tests, so we revert to a custom variable - that can hopefully make it up to the pybuild toolchain - - I looked at DEB_BUILD_OPTIONS=network, but that is not standard - and only mentionned once here: - - https://lists.debian.org/debian-devel/2009/09/msg00992.html - - DEB_BUILD_OPTIONS is also not set by default, so it's not a good - way to detect Debian package builds - - pbuilder uses USENETWORK=no/yes, schroot uses UNSHARE_NET, but - those are not standard either, see: - - https://github.com/spotify/dh-virtualenv/issues/77 - https://github.com/codelibre-net/schroot/blob/2e3d015a759d2b5106e851af34c8d5974d84f18e/lib/schroot/chroot/facet/unshare.cc - """ - - if ('PYTEST_USENETWORK' in os.environ - and 'no' in os.environ.get('PYTEST_USENETWORK', '')): - return unittest.skip('network tests disabled (PYTEST_USENETWORK=no)') - else: - return lambda func: func +from test_lib import TestTimeLimit, AlarmException, find_test_file, skipUnlessNetwork, skipIfDatePassed @skipUnlessNetwork() @@ -87,6 +52,7 @@ the network forever""" except AlarmException: raise unittest.case._ExpectedFailure(sys.exc_info()) + @skipIfDatePassed('2017-02-25T00:00:00UTC') def test_special_key(self): """test a key that sign_key had trouble with""" self.assertTrue(self.gpg.import_data(open(find_test_file('96F47C6A.asc')).read())) @@ -102,14 +68,5 @@ the network forever""" del self.gpg -@skipUnlessNetwork() -class KeyserverTests(test_ui.BaseTestCase): - args = ['--keyserver', 'pool.sks-keyservers.net'] - pattern = '7B75921E' - - def test_find_key(self): - """this should find the key on the keyservers""" - self.ui.find_key() - if __name__ == '__main__': unittest.main() diff --git a/monkeysign/tests/test_ui.py b/monkeysign/tests/test_ui.py index c3a92f9f16ce24f7efb3e857d29536a4a6d049ca..02e166e985cc9dfcf752baa359be8bf03382d831 100755 --- a/monkeysign/tests/test_ui.py +++ b/monkeysign/tests/test_ui.py @@ -28,7 +28,10 @@ import pkg_resources from pkg_resources import ResolutionError import sys import re -import io +from io import StringIO +import logging +import logging.handlers + import tempfile # monkeypatch 2.7 unittest to support missing functions @@ -72,14 +75,24 @@ from monkeysign.gpg import TempKeyring, GpgRuntimeError import test_lib # optimized because called often -from test_lib import find_test_file, skipIfDatePassed +from test_lib import find_test_file, skipIfDatePassed, skipUnlessNetwork +logger = logging.getLogger(__name__) class CliBaseTest(unittest.TestCase): def setUp(self): self.argv = sys.argv sys.argv = [ 'monkeysign', '--no-mail' ] + if '--debug' not in self.argv: + # Save the logging handlers on the root logger to a variable + # and replace them with a NullHandler (the null handler + # prevents logging calls from trying to add a stream handler + # back). This stops output from the tested functions from + # printing to the console and cluttering things up. + self.logging_handlers = logging.getLogger().handlers + logging.getLogger().handlers = [logging.NullHandler()] + def execute(self): '''execute the monkeysign script directly @@ -92,7 +105,7 @@ class CliBaseTest(unittest.TestCase): ''' directory, basename = os.path.split(self.argv[0]) path, directory = os.path.split(os.path.realpath(directory)) - if directory == 'scripts' or basename == 'setup.py': + if directory == 'scripts' or basename == 'setup.py' or 'pytest' in basename: # default to run from source dir. this is necessary for # ./scripts/monkeysign --test and ./setup.py test script = os.path.dirname(__file__) + '/../../scripts/monkeysign' @@ -129,6 +142,10 @@ class CliBaseTest(unittest.TestCase): def tearDown(self): sys.argv = self.argv + if '--debug' not in self.argv: + # Restore the logging handlers we removed in the setup function + logging.getLogger().handlers = self.logging_handlers + @unittest.skipUnless(Mock, 'mock library missing') class CliTestCase(CliBaseTest): @@ -155,7 +172,7 @@ class CliTestCase(CliBaseTest): """test to see if we output monkeysign and gpg versions""" sys.argv = ['monkeysign', '--version'] stderrbak = sys.stderr - sys.stderr = io.StringIO() + sys.stderr = StringIO() with self.assertRaises(SystemExit): self.execute() self.assertIn('Monkeysign: ', sys.stderr.getvalue()) @@ -181,7 +198,7 @@ class CliTestCase(CliBaseTest): args = self.parser.parse_args(['--local', '--smtpserver', 'localhost', '--tls', 'foo']) # first test parts of save_config() lines = self.parser.args_to_config(args) - out = io.StringIO() + out = StringIO() self.parser.write_config(lines, out) out = out.getvalue() self.assertIn('smtpserver=localhost', out) @@ -198,7 +215,7 @@ class CliTestCase(CliBaseTest): self.assertTrue(args.local) -@skipIfDatePassed('2017-06-01T00:00:00UTC') +@skipIfDatePassed('2019-06-05T00:00:00UTC') class CliTestDialog(CliBaseTest): def setUp(self): CliBaseTest.setUp(self) @@ -235,13 +252,14 @@ this tests for bug #716675""" self.write_to_callback("\n\n", callback) # say 'default' twice -@skipIfDatePassed('2017-06-01T00:00:00UTC') +@skipIfDatePassed('2019-06-05T00:00:00UTC') class CliTestSpacedFingerprint(CliTestDialog): def setUp(self): CliTestDialog.setUp(self) sys.argv.pop() # remove the uid from parent class sys.argv += '8DC9 01CE 6414 6C04 8AD5 0FBB 7921 5252 7B75 921E'.split() + class BaseTestCase(unittest.TestCase): pattern = None args = [] @@ -250,10 +268,13 @@ class BaseTestCase(unittest.TestCase): self.args = [ '--no-mail' ] + self.args + [ x for x in sys.argv[1:] if x.startswith('-') ] if self.pattern is not None: self.args += [ self.pattern ] + # do not read system-wide configs in tests + MonkeysignArgumentParser.configs = [] self.ui = MonkeysignUi(self.args) self.ui.keyring = TempKeyring() self.ui.prepare() # needed because we changed the base keyring + class BasicTests(BaseTestCase): pattern = '7B75921E' @@ -266,18 +287,33 @@ class BasicTests(BaseTestCase): self.assertFalse(os.path.exists(self.homedir)) -@skipIfDatePassed('2017-06-01T00:00:00UTC') +@skipIfDatePassed('2019-06-05T00:00:00UTC') class SigningTests(BaseTestCase): pattern = '7B75921E' def setUp(self): """setup a basic keyring capable of signing a local key""" BaseTestCase.setUp(self) + + if not self.ui.options.debug: + # Save the logging handlers on the root logger to a variable + # and replace them with a NullHandler (the null handler + # prevents logging calls from trying to add a stream handler + # back). This stops output from the tested functions from + # printing to the console and cluttering things up. + self.logging_handlers = logging.getLogger().handlers + logging.getLogger().handlers = [logging.NullHandler()] + self.assertTrue(self.ui.keyring.import_data(open(find_test_file('7B75921E.asc')).read())) self.assertTrue(self.ui.tmpkeyring.import_data(open(find_test_file('96F47C6A.asc')).read())) self.assertTrue(self.ui.keyring.import_data(open(find_test_file('96F47C6A.asc')).read())) self.assertTrue(self.ui.keyring.import_data(open(find_test_file('96F47C6A-secret.asc')).read())) + def tearDown(self): + if not self.ui.options.debug: + # Restore the logging handlers we removed in the setup function + logging.getLogger().handlers = self.logging_handlers + def test_find_key(self): """test if we can extract the key locally @@ -300,6 +336,14 @@ this duplicates tests from the gpg code, but is necessary to test later function self.ui.sign_key() self.assertGreaterEqual(len(self.ui.signed_keys), 1) + def test_sign_own_key(self): + """Test that signing a user's own key fails""" + self.ui.pattern = '96F47C6A' + self.test_copy_secrets() + self.ui.sign_key() + self.assertEquals(len(self.ui.signed_keys), 0) + self.ui.pattern = '7B75921E' + def test_gpg_conf(self): """test if gpg.conf default-key works""" # this fails with GnuPG 2.1 @@ -339,6 +383,22 @@ this duplicates tests from the gpg code, but is necessary to test later function if 'rev:' in uid: self.assertNotIn('sig:::1:A31E75E4323F39BD', uid) + def test_multiple_secrets(self): + """test if we pick the right key define in gpg.conf""" + # configure gpg to use the *first* test key as a default key + with open(os.path.join(self.ui.keyring.homedir, 'gpg.conf'), 'w') as f: + f.write('default-key 96F47C6A') + self.ui.prepare() + self.test_copy_secrets() + self.ui.keyring.import_data(open(find_test_file('323F39BD.asc')).read()) + self.ui.keyring.import_data(open(find_test_file('323F39BD-secret.asc')).read()) + self.test_copy_secrets() + self.ui.sign_key() + self.ui.tmpkeyring.context.call_command(['list-sigs', '7B75921E']) + # this is the secondary test key, it shouldn't have signed this + self.assertNotIn('sig:::1:A31E75E4323F39BD:', + self.ui.tmpkeyring.context.stdout) + def test_create_mail_multiple(self): """test if exported keys contain the right uid""" self.test_sign_key() @@ -358,42 +418,64 @@ this duplicates tests from the gpg code, but is necessary to test later function def test_export_key(self): """see if we export a properly encrypted key set""" - messages = [] - # collect messages instead of warning the user - self.ui.warn = messages.append - self.test_sign_key() - self.ui.export_key() - self.assertIsNone(self.ui.export_key(), 'sends mail?') - paste = messages.pop() - self.assertNotIn('BEGIN PGP PUBLIC KEY BLOCK', paste, - 'message not encrypted') - self.assertIn('BEGIN PGP MESSAGE', paste, 'message not encrypted') - self.assertNotIn('MIME-Version', paste, - 'message to paste has weird MIME headers') + # Create a handler to store messages being logged + memory_handler = logging.handlers.MemoryHandler(0) + # Add this handler to the monkeysign.ui logger + monkeysign_ui_logger = logging.getLogger('monkeysign.ui') + monkeysign_ui_logger.addHandler(memory_handler) + try: + self.test_sign_key() + self.ui.export_key() + self.assertIsNone(self.ui.export_key(), 'sends mail?') + + contains_exported_key = False + for record in memory_handler.buffer: + if (record.levelname == 'WARNING' and + "here's the encrypted signed public key you can paste in your email client" in record.getMessage()): + contains_exported_key = True + self.assertNotIn('BEGIN PGP PUBLIC KEY BLOCK', record.getMessage(), 'message not encrypted') + self.assertNotIn('MIME-Version', record.getMessage(), 'message to paste has weird MIME headers') + self.assertIn('BEGIN PGP MESSAGE', record.getMessage(), 'message not encrypted') + break + self.assertTrue(contains_exported_key, 'no exported key logged') + finally: + # Remove the handler when we're done. + monkeysign_ui_logger.removeHandler(memory_handler) def test_sendmail(self): """see if we can generate a proper commandline to send email""" self.test_sign_key() - messages = [] - # collect messages instead of warning the user - self.ui.warn = messages.append - self.ui.options.nomail = False - self.ui.options.user = 'unittests@localhost' - self.ui.options.to = 'devnull@localhost' - self.ui.options.mta = "dd status=none of='" + \ - self.ui.keyring.homedir + "/%(to)s'" - self.assertTrue(self.ui.export_key(), 'fails to send mail') - filename = '%s/%s' % (self.ui.keyring.homedir, self.ui.options.to) - self.assertGreater(os.path.getsize(filename), 0, - 'mail properly created') - self.assertIn('sent message to %s with dd' % self.ui.options.to, - messages.pop(), - 'missing information to user') - self.ui.options.to = 'devnull; touch bad' - self.assertTrue(self.ui.export_key(), - 'fails to send email to weird address') - self.assertFalse(os.path.exists('bad'), - 'vulnerable to command injection') + # Create a handler to store messages being logged + memory_handler = logging.handlers.MemoryHandler(0) + # Add this handler to the monkeysign.ui logger + monkeysign_ui_logger = logging.getLogger('monkeysign.ui') + monkeysign_ui_logger.addHandler(memory_handler) + try: + self.ui.options.nomail = False + self.ui.options.user = 'unittests@localhost' + self.ui.options.to = 'devnull@localhost' + self.ui.options.mta = "dd status=none of='" + \ + self.ui.keyring.homedir + "/%(to)s'" + self.assertTrue(self.ui.export_key(), 'fails to send mail') + filename = '%s/%s' % (self.ui.keyring.homedir, self.ui.options.to) + self.assertGreater(os.path.getsize(filename), 0, + 'mail properly created') + + contains_information_for_user = False + for record in memory_handler.buffer: + if (record.levelname == 'WARNING' and + 'sent message to %s with dd' % self.ui.options.to in record.getMessage()): + contains_information_for_user = True + self.assertTrue(contains_information_for_user, 'missing information to user') + + self.ui.options.to = 'devnull; touch bad' + self.assertTrue(self.ui.export_key(), + 'fails to send email to weird address') + self.assertFalse(os.path.exists('bad'), + 'vulnerable to command injection') + finally: + # Remove the handler when we're done. + monkeysign_ui_logger.removeHandler(memory_handler) def test_mua(self): self.test_sign_key() @@ -424,7 +506,7 @@ this duplicates tests from the gpg code, but is necessary to test later function os.unlink(outputfile) -@skipIfDatePassed('2017-06-01T00:00:00UTC') +@skipIfDatePassed('2019-06-05T00:00:00UTC') class EmailFactoryTest(BaseTestCase): pattern = '7B75921E' @@ -517,6 +599,8 @@ class FakeKeyringTests(BaseTestCase): """test if we can find a key on the local keyring""" self.ui.find_key() + +@skipUnlessNetwork() class NonExistentKeyTests(BaseTestCase, test_lib.TestTimeLimit): """test behavior with a key that can't be found""" @@ -532,5 +616,12 @@ class NonExistentKeyTests(BaseTestCase, test_lib.TestTimeLimit): except test_lib.AlarmException: raise unittest.case._ExpectedFailure(sys.exc_info()) -if __name__ == '__main__': - unittest.main() + +@skipUnlessNetwork() +class KeyserverTests(BaseTestCase): + args = ['--keyserver', 'pool.sks-keyservers.net'] + pattern = '7B75921E' + + def test_find_key(self): + """this should find the key on the keyservers""" + self.ui.find_key() diff --git a/monkeysign/ui.py b/monkeysign/ui.py index 311e3307d2d0df15fdacb2b4d30db65f1eb39803..e29be42d4d8cd01bc277761e24ad6c1946de7c69 100644 --- a/monkeysign/ui.py +++ b/monkeysign/ui.py @@ -21,6 +21,7 @@ import monkeysign # gpg interface from monkeysign.gpg import Keyring, TempKeyring, GpgRuntimeError, Context import monkeysign.translation +import warnings import errno # mail functions @@ -52,7 +53,9 @@ import shutil import socket import socks import tempfile +import logging +logger = logging.getLogger(__name__) class RunTests(argparse._VersionAction): '''argparse Action handler to run tests @@ -68,6 +71,23 @@ class RunTests(argparse._VersionAction): sys.argv.remove('--test') if '--version' in sys.argv: sys.argv.remove('--version') + + # If there aren't already handlers, set the logging level and + # format based on the the command line options passed + # in. Also, only print the <TIME> - <LEVEL> - <MODULE> prefix + # for log messages when debug mode has been requested. + # + # We're doing this as well as in MonkeysignUi.__init__ because + # when running the tests we don't call MonkeysignUi.__init__ + # until much later. + if not logging.getLogger().handlers: + if '--debug' in sys.argv or '-d' in sys.argv: + logging.getLogger().setLevel(logging.DEBUG) + log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + else: + log_format = "%(message)s" + logging.basicConfig(format=log_format) + testdir = os.path.join(os.path.dirname(__file__), 'tests') suite = unittest.TestLoader().discover(testdir) results = unittest.TextTestRunner().run(suite) @@ -136,14 +156,14 @@ class MonkeysignArgumentParser(argparse.ArgumentParser): self.add_argument('-s', '--smtpserver', '--smtp', help=_('SMTP server to use, use a colon to specify ' 'the port number if non-default (%(port)d).' - ' willl attempt to use STARTTLS to secure ' - 'the connexion and fail if unsupported ' + ' will attempt to use STARTTLS to secure ' + 'the connection and fail if unsupported ' '(default: deliver using the --mta ' 'command)') % {'port': smtplib.SMTP_PORT}) self.add_argument('--tls', action='store_true', - help=_('use a complete TLS connexion instead of ' - 'using STARTTLS to upgrade the connexion. ' + help=_('use a complete TLS connection instead of ' + 'using STARTTLS to upgrade the connection. ' 'will change the default SMTP port to ' '%(port)d') % {'port': smtplib.SMTP_SSL_PORT}) @@ -159,13 +179,12 @@ class MonkeysignArgumentParser(argparse.ArgumentParser): 'passed on the commandline in the "%%(to)s"' ' field, or the command must parse the ' '"To:" header (default: %(default)s)')) - default_mua = "xdg-email --utf8 --to '%%(to)s' --subject '%%(subject)s' --body '%%(body)s' --attach '%%(attach)s'" + default_mua = "xdg-email --utf8 --to '%(to)s' --subject '%(subject)s' --body '%(body)s' --attach '%(attach)s'" self.add_argument('--mua', nargs='?', default=None, const=default_mua, - help=_('Mail User Agent to use to send mail. all ' - 'parameters are passed on the commandline,' - 'overrides --mta. ' - '(default: %s when specified)') - % default_mua) + help=_('Mail User Agent to use to send mail. all ' + 'parameters are passed on the commandline,' + 'overrides --mta. ' + '(default: %(const)s when specified)')) self.add_argument('--nomail', '--no-mail', action='store_true', help=_('do not send email at all')) self.add_argument('-t', '--to', @@ -265,7 +284,9 @@ class MonkeysignArgumentParser(argparse.ArgumentParser): self.write_config(lines, config) if close: config.close() - # self.ui.log() except that we don't have logging yet + + logger.info("Saving config") + return True def args_to_config(self, args): @@ -353,10 +374,26 @@ configuration files are parsed by default: %s""" def __init__(self, args = None): # the options that determine how we operate, from the parse_args() - self.options = {} + self.parser = MonkeysignArgumentParser(ui=self) + self.options = self.parser.parse_args(args=args) + + # If there aren't already handlers, set the logging level and + # format based on the the command line options passed + # in. Also, only print the <TIME> - <LEVEL> - <MODULE> prefix + # for log messages when debug mode has been requested. + if not logging.getLogger().handlers: + if self.options.debug: + logging.getLogger().setLevel(logging.DEBUG) + log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + elif self.options.verbose: + logging.getLogger().setLevel(logging.INFO) + log_format = "%(message)s" + else: + log_format = "%(message)s" + logging.basicConfig(format=log_format) # the key we are signing, can be a keyid or a uid pattern - self.pattern = None + self.pattern = self.options.pattern # the regular keyring we suck secrets and maybe the key to be signed from self.keyring = Keyring() @@ -372,13 +409,7 @@ configuration files are parsed by default: %s""" # temporary, to keep track of the OpenPGPkey we are signing self.signing_key = None - self.parser = MonkeysignArgumentParser(ui=self) - self.options = self.parser.parse_args(args=args) - self.pattern = self.options.pattern - - # set a default logging mechanism - self.logfile = sys.stderr - self.log(_('Initializing UI')) + logger.info(_('Initializing UI')) # create the temporary keyring # XXX: i would prefer this to be done outside the constructor @@ -389,7 +420,7 @@ configuration files are parsed by default: %s""" def __exit__(self, exc_type, exc_value, traceback): # this is implicit in the garbage collection, but tell the user anyways - self.log(_('deleting the temporary keyring %s') % self.tmpkeyring.homedir) + logger.info(_('deleting the temporary keyring %s') % self.tmpkeyring.homedir) if exc_type is NotImplementedError: self.abort(str(exc_value)) @@ -398,9 +429,6 @@ configuration files are parsed by default: %s""" # initialize the temporary keyring directory self.tmpkeyring = TempKeyring() - if self.options.debug: - self.tmpkeyring.context.debug = self.logfile - self.keyring.context.debug = self.logfile if self.options.keyserver is not None: self.tmpkeyring.context.set_option('keyserver', self.options.keyserver) if self.options.user is not None: @@ -423,7 +451,7 @@ configuration files are parsed by default: %s""" m += [str(e)] self.abort(_('cannot open SOCKS proxy %s:%d: %s') % m) else: - self.log(_('SOCKS proxy %s:%d appears operational') % self.options.socks) + logger.info(_('SOCKS proxy %s:%d appears operational'), self.options.socks) # this should be --use-tor, but: # 1. that is available only in undetermined versions of GPG 2.1.x # 2. it is not available in GPG 1.x legacy, which we still support @@ -433,7 +461,7 @@ configuration files are parsed by default: %s""" self.tmpkeyring.context.set_option('keyserver-options', ks_opts) # copy the gpg.conf from the real keyring try: - self.log(_('copying your gpg.conf in temporary keyring')) + logger.info(_('copying your gpg.conf in temporary keyring')) shutil.copy(self.keyring.homedir + '/gpg.conf', self.tmpkeyring.homedir) except IOError as e: # no such file or directory is alright: it means the use @@ -449,7 +477,7 @@ configuration files are parsed by default: %s""" # cargo-culted from caff, thanks guilhem! src = self.keyring.get_agent_socket() dst = self.tmpkeyring.get_agent_socket() - self.log(_('installing symlinks for sockets from %s to %s') % (src, dst)) + logger.info(_('installing symlinks for sockets from %s to %s'), src, dst) try: os.unlink(dst) except OSError as e: @@ -485,12 +513,23 @@ configuration files are parsed by default: %s""" def warn(self, message): """display an warning message + DEPRECATED: This method has been deprecated. Use Logger.warning instead. + this should not interrupt the flow of the program, but must be visible to the user""" - print(message.encode('utf-8')) + warning = ("This method is deprecated, and will be removed in a future version. " + "As alternative, use Logger.warning()") + warnings.warn(warning, DeprecationWarning) + logger.warning(message) def log(self, message): - """log an informational message if verbose""" - if self.options.verbose or self.options.debug: print(message, file=self.logfile) + """log an informational message if verbose + + DEPRECATED: This method has been deprecated. Use Logger.warning instead. + """ + warning = ("This method is deprecated, and will be removed in a future version. " + "As alternative, use Logger.info()") + warnings.warn(warning, DeprecationWarning) + logger.info(message) def yes_no(self, prompt, default = True): """default UI is not interactive, so we assume yes all the time""" @@ -511,12 +550,12 @@ this should not interrupt the flow of the program, but must be visible to the us def find_key(self): """find the key to be signed somewhere""" # 1.b) from the local keyring - self.log(_('looking for key %s in your keyring') % self.pattern) + logger.info(_('looking for key %s in your keyring'), self.pattern) if not self.tmpkeyring.import_data(self.keyring.export_data(self.pattern)): - self.log(_('key not in local keyring')) + logger.info(_('key not in local keyring')) # 1.a) if allowed, from the keyservers - self.log(_('fetching key %s from keyserver') % self.pattern) + logger.info(_('fetching key %s from keyserver'), self.pattern) if not re.search('^[0-9A-F]*$', self.pattern, re.IGNORECASE): # this is not a keyid # the problem here is that we need to implement --search-keys, and it's a pain @@ -536,18 +575,32 @@ we copy all keys because we do not want to guess which keys gpg will chose. it could vary based on default-key, for example, or some weird ordering. """ - self.log(_('copying your public key to temporary keyring in %s') % self.tmpkeyring.homedir) - # detect the proper uid - keys = self.keyring.get_keys(self.options.user, True, False) + logger.info(_('copying your public key to temporary keyring in %s') % self.tmpkeyring.homedir) + + # detect default key setting + default_key = self.options.user + try: + with open(os.path.join(self.tmpkeyring.homedir, + 'gpg.conf'), 'r') as conf: + result = re.search(r'^default-key\s+(.*)$', conf.read(), re.M) + if result: + default_key = result.group(1) + logging.info(_('found default-key setting: %s'), default_key) + except IOError as e: + if e.errno != errno.ENOENT: + raise + logging.info(_('looking for key %s'), default_key) + # detect the proper uid + keys = self.keyring.get_keys(default_key, True, False) for fpr, key in keys.iteritems(): - self.log(_('found secret key: %s') % key) + logger.info(_('found secret key: %s'), key) if not key.invalid and not key.disabled and not key.expired and not key.revoked: self.signing_key = key # export public key material associated with all private keys # XXX: we should only do export-minimal here, but passing options down is a pain. if not self.tmpkeyring.import_data(self.keyring.export_data(key.fpr)): - self.warning(_('could not export public key material of private key %s') % key.fpr) + logger.warning(_('could not export public key material of private key %s'), key.fpr) if self.signing_key is None: self.abort(_('could not find public key material for any private key, do you have an OpenPGP key?')) @@ -559,9 +612,17 @@ ordering. # this shouldn't happen unless caller forgot to call copy_secrets assert(keys is not None) # nosec - self.log(_('found %d keys matching your request') % len(keys)) + logger.info(_('found %d keys matching your request'), len(keys)) + + secret_keys = self.keyring.get_keys(self.options.user, True, False) for key in keys: + # Make sure the user isn't signing their own key + for secret_key in secret_keys.values(): + if keys[key] == secret_key: + logger.warning(_('That is your own key, so it is already certified')) + return False + alluids = self.yes_no(_("""\ Signing the following key @@ -576,7 +637,7 @@ Sign all identities? [y/N] \ else: pattern = self.choose_uid(_('Choose the identity to sign'), keys[key]) if not pattern: - self.log(_('no identity chosen')) + logger.info(_('no identity chosen')) return False if not self.options.to: self.options.to = pattern @@ -586,18 +647,18 @@ Sign all identities? [y/N] \ if not self.yes_no(_('Really sign key? [y/N] '), False): continue if not self.tmpkeyring.sign_key(pattern, alluids): - self.warn(_('key signing failed')) + logger.warning(_('key signing failed')) else: self.signed_keys[key] = keys[key] if self.options.local: - self.log(_('making a non-exportable signature')) + logger.info(_('making a non-exportable signature')) self.tmpkeyring.context.set_option('export-options', 'export-minimal') # this is inefficient - we could save a copy if we would fetch the key directly if not self.keyring.import_data(self.tmpkeyring.export_data(self.pattern)): self.abort(_('could not import public key back into public keyring, something is wrong')) if not self.keyring.sign_key(pattern, alluids, True): - self.warn(_('local key signing failed')) + logger.warning(_('local key signing failed')) def export_key(self): if self.options.user is not None and '@' in self.options.user: @@ -606,24 +667,26 @@ Sign all identities? [y/N] \ from_user = self.signing_key.uidslist[0].uid if len(self.signed_keys) < 1: - self.warn(_('no key signed, nothing to export')) - + logger.warning(_('no key signed, nothing to export')) + + ret = True for fpr, key in self.signed_keys.items(): if self.chosen_uid is None: for uid in key.uids.values(): try: msg = EmailFactory(self.tmpkeyring.export_data(fpr), fpr, uid.uid, from_user, self.options.to) except GpgRuntimeError as e: - self.warn(_('failed to create email: %s') % e) + logger.warning(_('failed to create email: %s'), e) break - return self.sendmail(msg) + ret = ret and self.sendmail(msg) else: try: msg = EmailFactory(self.tmpkeyring.export_data(fpr), fpr, self.chosen_uid, from_user, self.options.to) except GpgRuntimeError as e: - self.warn(_('failed to create email: %s') % e) + logger.warning(_('failed to create email: %s'), e) break - return self.sendmail(msg) + ret = self.sendmail(msg) + return ret def sendmail(self, msg): """actually send the email @@ -654,7 +717,7 @@ expects an EmailFactory email, but will not mail if nomail is set""" try: server.starttls() except smtplib.SMTPException: - self.warn(_('SMTP server does not support STARTTLS')) + logger.warning(_('SMTP server does not support STARTTLS')) if self.options.smtpuser: self.abort(_('aborting authentication as credentials would have been sent in clear text')) if self.options.smtpuser: @@ -664,9 +727,9 @@ expects an EmailFactory email, but will not mail if nomail is set""" try: server.sendmail(msg.mailfrom.encode('utf-8'), msg.mailto.encode('utf-8'), msg.as_string().encode('utf-8')) except smtplib.SMTPException as e: - self.warn(_('failed to send email: %s') % e) + logger.warning(_('failed to send email: %s'), e) else: - self.warn(_('sent message through SMTP server %s to %s') % (self.options.smtpserver, msg.mailto)) + logger.warning(_('sent message through SMTP server %s to %s') % (self.options.smtpserver, msg.mailto)) server.quit() return True elif not self.options.nomail: @@ -691,19 +754,19 @@ expects an EmailFactory email, but will not mail if nomail is set""" for x in shlex.split(self.options.mta)] except ValueError as e: if 'incomplete format' in str(e): - self.warn(_('invalid command (%s) specified to send email: %s') - % (self.options.mua or self.options.mta, str(e))) + logger.warning(_('invalid command (%s) specified to send email: %s'), + (self.options.mua or self.options.mta, str(e))) return False else: raise - self.log('running command %s' % command) + logger.info('running command %s', command) try: p = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # nosec except OSError as e: - self.warn(_('cannot find MTA %s, try specifying --mua, --mta or --smtp: %s') + logger.warning(_('cannot find MTA %s, try specifying --mua, --mta or --smtp: %s') % (self.options.mua, repr(e))) return False @@ -716,21 +779,21 @@ expects an EmailFactory email, but will not mail if nomail is set""" self.acknowledge('when you have finished writing the email') keyfile.close() # remove the tmpfile if p.returncode == 0: - self.warn(_('sent message to %(destination)s with %(command)s') - % {'destination': msg.mailto, - 'command': self.options.mua or self.options.mta}) + logger.warning(_('sent message to %(destination)s with %(command)s'), + {'destination': msg.mailto, + 'command': self.options.mua or self.options.mta}) else: - self.warn(_('failed sending message to %(destination)s with %(command)s: %(error)s') - % {'destination': msg.mailto, - 'command': self.options.mua or self.options.mta, - 'error': self.mailer_output + self.mailer_error}) + logger.warning(_('failed sending message to %(destination)s with %(command)s: %(error)s'), + {'destination': msg.mailto, + 'command': self.options.mua or self.options.mta, + 'error': self.mailer_output + self.mailer_error}) return p.returncode == 0 else: # okay, no mail, just dump the exported key then - self.warn(_("""\ + logger.warning(_("""\ not sending email to %s, as requested, here's the encrypted signed public key you can paste in your email client: -%s""") % (msg.mailto, msg.encrypted())) +%s"""), msg.mailto, msg.encrypted()) class EmailFactory: diff --git a/po/de.po b/po/de.po new file mode 100644 index 0000000000000000000000000000000000000000..47d2f9bed7e7885353f07687afe9b63b25364b41 --- /dev/null +++ b/po/de.po @@ -0,0 +1,718 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-08-14 23:21-0400\n" +"PO-Revision-Date: 2018-02-01 23:37+0000\n" +"Last-Translator: Jan Christian Grünhage <jan.christian@gruenhage.xyz>\n" +"Language-Team: German " +"<https://hosted.weblate.org/projects/monkeysphere/monkeysign/de/>\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 2.19-dev\n" + +#: ../monkeysign/cli.py:26 +msgid "" +"sign a key in a safe fashion.\n" +"\n" +"This command signs a key based on the fingerprint or user id\n" +"specified on the commandline, encrypt the result and mail it to the\n" +"user. This leave the choice of publishing the certification to that\n" +"person and makes sure that person owns the identity signed.\n" +"\n" +"This program assumes you have gpg-agent configured to prompt for\n" +"passwords." +msgstr "" +"Signiere einen Schlüssel auf eine sichere Weise.\n" +"\n" +"Dieses Kommando signiert einen Schlüssel basierend auf dem Fingerabdruck " +"oder der Nutzerkennung\n" +"die auf der Kommandozeile spezifiziert wird, verschlüsselt das Ergebnis und " +"mailt es dem Nutzer.\n" +"Das überlässt die Wahl ob die Signatur veröffentlicht wird dem Nutzer, dem " +"die signierte Identität gehört.\n" +"\n" +"Dieses Programm nimmt an, das gpg-agent konfiguriert ist nach Passwörtern zu " +"fragen." + +#: ../monkeysign/cli.py:37 +msgid "%prog [options] <keyid>" +msgstr "" + +#: ../monkeysign/cli.py:38 +msgid "<keyid>: a GPG fingerprint or key id" +msgstr "<keyid>: ein GPG Fingerabdruck oder eine Schlüsselkennung" + +#: ../monkeysign/cli.py:45 +msgid "wrong number of arguments, use -h for full help" +msgstr "Falsche Anzahl an Argumenten, siehe -h für mehr Hilfe" + +#: ../monkeysign/cli.py:57 +#, python-format +msgid "reset GPG_TTY to %s" +msgstr "" + +#: ../monkeysign/cli.py:65 +#, python-format +msgid "" +"Preparing to sign with this key\n" +"\n" +"%s" +msgstr "" + +#: ../monkeysign/cli.py:100 +#, python-format +msgid " (1-%d or full UID, control-c to abort): " +msgstr "" + +#: ../monkeysign/cli.py:104 +msgid "invalid uid" +msgstr "" + +#: ../monkeysign/gpg.py:209 +#, python-format +msgid "could not find pattern '%s' in input, last skipped '%s'" +msgstr "" + +#: ../monkeysign/gpg.py:329 +#, python-format +msgid "verifying file %s failed: %s." +msgstr "" + +#: ../monkeysign/gpg.py:366 ../monkeysign/gpg.py:386 +#, python-format +msgid "unexpected GPG exit code in list-keys: %d" +msgstr "" + +#: ../monkeysign/gpg.py:398 +#, python-format +msgid "encryption to %s failed: %s." +msgstr "" + +#: ../monkeysign/gpg.py:409 +#, python-format +msgid "decryption failed: %s" +msgstr "" + +#: ../monkeysign/gpg.py:471 ../monkeysign/gpg.py:473 +#, python-format +msgid "cannot sign: %s" +msgstr "" + +#: ../monkeysign/gpg.py:483 +msgid "you already signed that key" +msgstr "" + +#: ../monkeysign/gpg.py:486 ../monkeysign/gpg.py:519 +#, python-format +msgid "unable to open key for editing: %s" +msgstr "" + +#: ../monkeysign/gpg.py:494 +msgid "unable to prompt for passphrase, is gpg-agent running?" +msgstr "" + +#: ../monkeysign/gpg.py:530 +msgid "key is expired, cannot sign" +msgstr "" + +#: ../monkeysign/gpg.py:532 +#, python-format +msgid "cannot sign, unknown error from gpg: %s" +msgstr "" + +#: ../monkeysign/gpg.py:537 +msgid "password confirmation failed" +msgstr "" + +#: ../monkeysign/gpg.py:708 +#, python-format +msgid "record type '%s' not implemented" +msgstr "" + +#: ../monkeysign/gtkui.py:40 +msgid "" +"sign a key in a safe fashion using a webcam to scan for qr-codes\n" +"\n" +"This command will fire up a graphical interface and turn on the webcam\n" +"(if available) on this computer. It will also display a qr-code of\n" +"your main OpenPGP key.\n" +"\n" +"The webcam is used to capture an OpenPGP fingerprint represented as a\n" +"qrcode (or whatever the zbar library can parse) and then go through a\n" +"signing process.\n" +"\n" +"The signature is then encrypted and mailed to the user. This leave the\n" +"choice of publishing the certification to that person and makes sure\n" +"that person owns the identity signed.\n" +"\n" +"This program assumes you have gpg-agent configure to prompt for\n" +"passwords.\n" +msgstr "" + +#: ../monkeysign/gtkui.py:120 +msgid "okay, signing" +msgstr "" + +#: ../monkeysign/gtkui.py:123 +msgid "user denied signature" +msgstr "" + +#: ../monkeysign/gtkui.py:152 +msgid "Monkeysign (scan)" +msgstr "" + +#: ../monkeysign/gtkui.py:184 +msgid "_File" +msgstr "" + +#: ../monkeysign/gtkui.py:185 +msgid "Open image..." +msgstr "" + +#: ../monkeysign/gtkui.py:186 +msgid "_Save QR code as..." +msgstr "" + +#: ../monkeysign/gtkui.py:187 +msgid "_Print QR code..." +msgstr "" + +#: ../monkeysign/gtkui.py:189 +msgid "Copy image to clipboard" +msgstr "" + +#: ../monkeysign/gtkui.py:189 +msgid "_Copy QR code" +msgstr "" + +#: ../monkeysign/gtkui.py:190 +msgid "Choose identity" +msgstr "" + +#: ../monkeysign/gtkui.py:190 +msgid "Identity" +msgstr "" + +#: ../monkeysign/gtkui.py:191 +msgid "Select video device to use" +msgstr "" + +#: ../monkeysign/gtkui.py:191 +msgid "Video device" +msgstr "" + +#: ../monkeysign/gtkui.py:192 +msgid "_Quit" +msgstr "" + +#: ../monkeysign/gtkui.py:201 +msgid "Disable video" +msgstr "" + +#: ../monkeysign/gtkui.py:245 +msgid "No video device detected." +msgstr "" + +#: ../monkeysign/gtkui.py:251 +msgid "" +"This is the output of your webcam, align a qrcode in the image to scan a " +"fingerprint." +msgstr "" + +#~ msgid "create the QR code display" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:269 +msgid "" +"This is a QR-code version of your PGP fingerprint. Scan this with another " +"monkeysign to transfer your fingerprint." +msgstr "" + +#~ msgid "list the secret keys for selection somewhere" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:291 ../monkeysign/gtkui.py:292 +msgid "Hide QR code" +msgstr "" + +#~ msgid "When window is resized, regenerate the QR code" +#~ msgstr "" + +#~ msgid "refresh the qrcode when the selected key changes" +#~ msgstr "" + +#~ msgid "draw the qrcode from the key fingerprint" +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked when a new video device is selected from the\n" +#~ " drop-down list. sets the new device for the zbar widget,\n" +#~ " which will eventually cause it to be opened and enabled\n" +#~ " " +#~ msgstr "" + +#~ msgid "Given a fingerprint, generate a QR code image with appropriate prefix" +#~ msgstr "" + +#~ msgid "Use a file chooser dialog to import an image containing a QR code" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:361 +msgid "cannot find signature for image file" +msgstr "" + +#: ../monkeysign/gtkui.py:363 +#, python-format +msgid "" +"The image provided cannot be verified using a trusted OpenPGP signature.\n" +"\n" +"Make sure the image comes from a trusted source (e.g. your own camera, which " +"you have never left unsurveilled) before signing this!\n" +"\n" +"DO NOT SIGN UNTRUSTED FINGERPRINTS!\n" +"\n" +"To get rid of this warning, if you really trust this image, use the " +"following command to sign the file\n" +"\n" +" gpg -s --detach %s\n" +msgstr "" + +#: ../monkeysign/gtkui.py:365 +msgid "image signature verified successfully" +msgstr "" + +#: ../monkeysign/gtkui.py:370 +msgid "Scan an image for QR codes" +msgstr "" + +#: ../monkeysign/gtkui.py:403 +msgid "data found in image!" +msgstr "" + +#~ msgid "" +#~ "Use a file chooser dialog to enable user to save the current QR code as a " +#~ "PNG image file" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:410 ../monkeysign/gtkui.py:435 +msgid "" +"No identity selected. Select one from the identiy menu or generate a OpenPGP " +"key if none is available." +msgstr "" + +#: ../monkeysign/gtkui.py:414 +msgid "Save QR code" +msgstr "" + +#~ msgid "copy the qrcode to the clipboard" +#~ msgstr "" + +#~ msgid "handler for the print QR code menu" +#~ msgstr "" + +#~ msgid "actually print the qr code" +#~ msgstr "" + +#~ msgid "Utility function to convert a PIL image instance to Pixbuf" +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked for pulsating progressbar\n" +#~ " " +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked when gpg key download is finished\n" +#~ " " +#~ msgstr "" + +#: ../monkeysign/gtkui.py:478 +msgid "fetching finished" +msgstr "" + +#~ msgid "" +#~ "callback invoked when a barcode is decoded by the zbar widget.\n" +#~ " checks for an openpgp fingerprint\n" +#~ " " +#~ msgstr "" + +#~ msgid "process zbar-scanned data" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:523 +msgid "zbar captured a frame, looking for 40 character hexadecimal fingerprint" +msgstr "" + +#: ../monkeysign/gtkui.py:534 ../monkeysign/ui.py:229 +#, python-format +msgid "looking for key %s in your keyring" +msgstr "" + +#: ../monkeysign/gtkui.py:547 +msgid "Please wait" +msgstr "" + +#: ../monkeysign/gtkui.py:549 +msgid "Retrieving public key from server..." +msgstr "" + +#: ../monkeysign/gtkui.py:563 +#, python-format +msgid "data found in barcode does not match a OpenPGP fingerprint pattern: %s" +msgstr "" + +#~ msgid "restart capture" +#~ msgstr "" + +#~ msgid "close the application" +#~ msgstr "" + +#~ msgid "" +#~ "User interface abstraction for monkeysign.\n" +#~ "\n" +#~ " This aims to factor out a common pattern to sign keys that is used\n" +#~ " regardless of the UI used.\n" +#~ "\n" +#~ " This is mostly geared at console/text-based and X11 interfaces,\n" +#~ " but could also be ported to other interfaces (touch-screen/phone\n" +#~ " interfaces would be interesting).\n" +#~ "\n" +#~ " The actual process is in main(), which outlines what the\n" +#~ " subclasses of this should be doing.\n" +#~ "\n" +#~ " You should have a docstring in derived classes, as it will be\n" +#~ " added to the 'usage' output.\n" +#~ "\n" +#~ " You should also set the usage and epilog parameters, see\n" +#~ " parse_args().\n" +#~ " " +#~ msgstr "" + +#~ msgid "parse the commandline arguments" +#~ msgstr "" + +#: ../monkeysign/ui.py:74 +msgid "show version information and quit" +msgstr "" + +#: ../monkeysign/ui.py:76 +msgid "request debugging information from GPG engine (lots of garbage)" +msgstr "" + +#: ../monkeysign/ui.py:78 +msgid "explain what we do along the way" +msgstr "" + +#: ../monkeysign/ui.py:80 +msgid "do not actually do anything" +msgstr "" + +#: ../monkeysign/ui.py:81 +msgid "user id to sign the key with" +msgstr "" + +#: ../monkeysign/ui.py:82 +msgid "certification level to sign the key with" +msgstr "" + +#: ../monkeysign/ui.py:84 +msgid "import in normal keyring a local certification" +msgstr "" + +#: ../monkeysign/ui.py:86 +msgid "keyserver to fetch keys from" +msgstr "" + +#: ../monkeysign/ui.py:87 +msgid "" +"SMTP server to use, use a colon to specify the port number if non-standard" +msgstr "" + +#: ../monkeysign/ui.py:88 +msgid "username for the SMTP server (default: no user)" +msgstr "" + +#: ../monkeysign/ui.py:89 +msgid "" +"password for the SMTP server (default: prompted, if --smtpuser is specified)" +msgstr "" + +#: ../monkeysign/ui.py:91 +msgid "Do not send email at all. (Default is to use sendmail.)" +msgstr "" + +#: ../monkeysign/ui.py:93 +msgid "" +"Override destination email for testing (default is to use the first uid on " +"the key or send email to each uid chosen)" +msgstr "" + +#: ../monkeysign/ui.py:136 +msgid "Initializing UI" +msgstr "" + +#: ../monkeysign/ui.py:147 +#, python-format +msgid "deleting the temporary keyring %s" +msgstr "" + +#: ../monkeysign/ui.py:172 +msgid "copied your gpg.conf in temporary keyring" +msgstr "" + +#~ msgid "" +#~ "\n" +#~ " General process\n" +#~ " ===============\n" +#~ "\n" +#~ " 1. fetch the key into a temporary keyring\n" +#~ " 1.a) if allowed (@todo), from the keyservers\n" +#~ " 1.b) from the local keyring (@todo try that first?)\n" +#~ " 2. copy the signing key secrets into the keyring\n" +#~ " 3. for every user id (or all, if -a is specified)\n" +#~ " 3.1. sign the uid, using gpg-agent\n" +#~ " 3.2. export and encrypt the signature\n" +#~ " 3.3. mail the key to the user\n" +#~ " 3.4. optionnally (-l), create a local signature and import in\n" +#~ " local keyring\n" +#~ " 4. trash the temporary keyring\n" +#~ " " +#~ msgstr "" + +#~ msgid "show a message to the user and abort program" +#~ msgstr "" + +#~ msgid "" +#~ "display an warning message\n" +#~ "\n" +#~ "this should not interrupt the flow of the program, but must be visible to " +#~ "the user" +#~ msgstr "" + +#~ msgid "log an informational message if verbose" +#~ msgstr "" + +#~ msgid "default UI is not interactive, so we assume yes all the time" +#~ msgstr "" + +#~ msgid "find the key to be signed somewhere" +#~ msgstr "" + +#: ../monkeysign/ui.py:231 +msgid "key not in local keyring" +msgstr "" + +#: ../monkeysign/ui.py:234 +#, python-format +msgid "fetching key %s from keyservers" +msgstr "" + +#: ../monkeysign/ui.py:238 +msgid "please provide a keyid or fingerprint, uids are not supported yet" +msgstr "" + +#: ../monkeysign/ui.py:241 +#, python-format +msgid "could not find key %s in your keyring or keyservers" +msgstr "" + +#~ msgid "" +#~ "import secret keys (but only the public part) from your keyring\n" +#~ "\n" +#~ "we use --secret-keyring instead of copying the secret key material,\n" +#~ "but we still need the public part in the temporary keyring for this to\n" +#~ "work.\n" +#~ msgstr "" + +#: ../monkeysign/ui.py:250 +#, python-format +msgid "copying your private key to temporary keyring in %s" +msgstr "" + +#: ../monkeysign/ui.py:258 +#, python-format +msgid "found secret key: %s" +msgstr "" + +#: ../monkeysign/ui.py:264 +msgid "no default secret key found, abort!" +msgstr "" + +#: ../monkeysign/ui.py:265 +#, python-format +msgid "signing key chosen: %s" +msgstr "" + +#: ../monkeysign/ui.py:269 +msgid "could not find public key material, do you have a GPG key?" +msgstr "" + +#~ msgid "sign the key uids, as specified" +#~ msgstr "" + +#: ../monkeysign/ui.py:276 +#, python-format +msgid "found %d keys matching your request" +msgstr "" + +#: ../monkeysign/ui.py:279 +#, python-format +msgid "" +"Signing the following key\n" +"\n" +"%s\n" +"\n" +"Sign all identities? [y/N] " +msgstr "" + +#: ../monkeysign/ui.py:291 +msgid "Choose the identity to sign" +msgstr "" + +#: ../monkeysign/ui.py:293 +msgid "no identity chosen" +msgstr "" + +#: ../monkeysign/ui.py:300 +msgid "Really sign key? [y/N] " +msgstr "" + +#: ../monkeysign/ui.py:303 +msgid "key signing failed" +msgstr "" + +#: ../monkeysign/ui.py:307 +msgid "making a non-exportable signature" +msgstr "" + +#: ../monkeysign/ui.py:312 +msgid "" +"could not import public key back into public keyring, something is wrong" +msgstr "" + +#: ../monkeysign/ui.py:314 +msgid "local key signing failed" +msgstr "" + +#: ../monkeysign/ui.py:322 +msgid "no key signed, nothing to export" +msgstr "" + +#: ../monkeysign/ui.py:330 ../monkeysign/ui.py:337 +#, python-format +msgid "failed to create email: %s" +msgstr "" + +#: ../monkeysign/ui.py:354 +#, python-format +msgid "Error connecting to SMTP server %s: %s" +msgstr "" + +#: ../monkeysign/ui.py:356 +#, python-format +msgid "Unexpected SMTP server error while talking to %s, code: %s (%s)" +msgstr "" + +#: ../monkeysign/ui.py:360 +msgid "SMTP server does not support STARTTLS" +msgstr "" + +#: ../monkeysign/ui.py:361 +msgid "authentication credentials will be sent in clear text" +msgstr "" + +#: ../monkeysign/ui.py:364 +#, python-format +msgid "enter SMTP password for server %s: " +msgstr "" + +#: ../monkeysign/ui.py:368 +#, python-format +msgid "sent message through SMTP server %s to %s" +msgstr "" + +#: ../monkeysign/ui.py:374 +#, python-format +msgid "sent message through sendmail to %s" +msgstr "" + +#: ../monkeysign/ui.py:377 +#, python-format +msgid "" +"not sending email to %s, as requested, here's the email message:\n" +"\n" +"%s" +msgstr "" + +#~ msgid "" +#~ "email generator\n" +#~ "\n" +#~ "this is a factory, ie. a class generating an object that represents\n" +#~ "the email and when turned into a string, is the actual\n" +#~ "mail.\n" +#~ msgstr "" + +#: ../monkeysign/ui.py:392 +msgid "Your signed OpenPGP key" +msgstr "" + +#: ../monkeysign/ui.py:395 +msgid "" +"\n" +"Please find attached your signed PGP key. You can import the signed\n" +"key by running each through `gpg --import`.\n" +"\n" +"If you have multiple user ids, each signature was sent in a separate\n" +"email to each user id.\n" +"\n" +"Note that your key was not uploaded to any keyservers. If you want\n" +"this new signature to be available to others, please upload it\n" +"yourself. With GnuPG this can be done using:\n" +"\n" +" gpg --keyserver pool.sks-keyservers.net --send-key <keyid>\n" +"\n" +"Regards,\n" +msgstr "" + +#~ msgid "" +#~ "email constructor\n" +#~ "\n" +#~ "we expect to find the following arguments:\n" +#~ "\n" +#~ "keydata: the signed public key material\n" +#~ "keyfpr: the fingerprint of that public key\n" +#~ "recipient: the recipient to encrypt the mail to\n" +#~ "mailfrom: who the mail originates from\n" +#~ "mailto: who to send the mail to (usually similar to recipient, but can be " +#~ "used to specify specific keyids" +#~ msgstr "" + +#~ msgid "this will remove any UID not matching the 'recipient' set in the class" +#~ msgstr "" + +#~ msgid "" +#~ "\n" +#~ " a multipart/mixed message containing a plain-text message\n" +#~ " explaining what this is, and a second part containing PGP data\n" +#~ " " +#~ msgstr "" + +#: ../monkeysign/ui.py:494 +#, python-format +msgid "signed PGP Key %s, uid %s" +msgstr "" + +#: ../monkeysign/ui.py:507 +msgid "This is a multi-part message in PGP/MIME format..." +msgstr "" + +#~ msgid "A non-wrapping formatter for OptionParse." +#~ msgstr "" diff --git a/po/el.po b/po/el.po new file mode 100644 index 0000000000000000000000000000000000000000..e1988b9ed62876eb426dea3050e8c078bb4e7621 --- /dev/null +++ b/po/el.po @@ -0,0 +1,704 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-08-14 23:21-0400\n" +"PO-Revision-Date: 2014-10-16 23:47-0400\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: el\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../monkeysign/cli.py:26 +msgid "" +"sign a key in a safe fashion.\n" +"\n" +"This command signs a key based on the fingerprint or user id\n" +"specified on the commandline, encrypt the result and mail it to the\n" +"user. This leave the choice of publishing the certification to that\n" +"person and makes sure that person owns the identity signed.\n" +"\n" +"This program assumes you have gpg-agent configured to prompt for\n" +"passwords." +msgstr "" + +#: ../monkeysign/cli.py:37 +msgid "%prog [options] <keyid>" +msgstr "" + +#: ../monkeysign/cli.py:38 +msgid "<keyid>: a GPG fingerprint or key id" +msgstr "" + +#: ../monkeysign/cli.py:45 +msgid "wrong number of arguments, use -h for full help" +msgstr "" + +#: ../monkeysign/cli.py:57 +#, python-format +msgid "reset GPG_TTY to %s" +msgstr "" + +#: ../monkeysign/cli.py:65 +#, python-format +msgid "" +"Preparing to sign with this key\n" +"\n" +"%s" +msgstr "" + +#: ../monkeysign/cli.py:100 +#, python-format +msgid " (1-%d or full UID, control-c to abort): " +msgstr "" + +#: ../monkeysign/cli.py:104 +msgid "invalid uid" +msgstr "" + +#: ../monkeysign/gpg.py:209 +#, python-format +msgid "could not find pattern '%s' in input, last skipped '%s'" +msgstr "" + +#: ../monkeysign/gpg.py:329 +#, python-format +msgid "verifying file %s failed: %s." +msgstr "" + +#: ../monkeysign/gpg.py:366 ../monkeysign/gpg.py:386 +#, python-format +msgid "unexpected GPG exit code in list-keys: %d" +msgstr "" + +#: ../monkeysign/gpg.py:398 +#, python-format +msgid "encryption to %s failed: %s." +msgstr "" + +#: ../monkeysign/gpg.py:409 +#, python-format +msgid "decryption failed: %s" +msgstr "" + +#: ../monkeysign/gpg.py:471 ../monkeysign/gpg.py:473 +#, python-format +msgid "cannot sign: %s" +msgstr "" + +#: ../monkeysign/gpg.py:483 +msgid "you already signed that key" +msgstr "" + +#: ../monkeysign/gpg.py:486 ../monkeysign/gpg.py:519 +#, python-format +msgid "unable to open key for editing: %s" +msgstr "" + +#: ../monkeysign/gpg.py:494 +msgid "unable to prompt for passphrase, is gpg-agent running?" +msgstr "" + +#: ../monkeysign/gpg.py:530 +msgid "key is expired, cannot sign" +msgstr "" + +#: ../monkeysign/gpg.py:532 +#, python-format +msgid "cannot sign, unknown error from gpg: %s" +msgstr "" + +#: ../monkeysign/gpg.py:537 +msgid "password confirmation failed" +msgstr "" + +#: ../monkeysign/gpg.py:708 +#, python-format +msgid "record type '%s' not implemented" +msgstr "" + +#: ../monkeysign/gtkui.py:40 +msgid "" +"sign a key in a safe fashion using a webcam to scan for qr-codes\n" +"\n" +"This command will fire up a graphical interface and turn on the webcam\n" +"(if available) on this computer. It will also display a qr-code of\n" +"your main OpenPGP key.\n" +"\n" +"The webcam is used to capture an OpenPGP fingerprint represented as a\n" +"qrcode (or whatever the zbar library can parse) and then go through a\n" +"signing process.\n" +"\n" +"The signature is then encrypted and mailed to the user. This leave the\n" +"choice of publishing the certification to that person and makes sure\n" +"that person owns the identity signed.\n" +"\n" +"This program assumes you have gpg-agent configure to prompt for\n" +"passwords.\n" +msgstr "" + +#: ../monkeysign/gtkui.py:120 +msgid "okay, signing" +msgstr "" + +#: ../monkeysign/gtkui.py:123 +msgid "user denied signature" +msgstr "" + +#: ../monkeysign/gtkui.py:152 +msgid "Monkeysign (scan)" +msgstr "" + +#: ../monkeysign/gtkui.py:184 +msgid "_File" +msgstr "" + +#: ../monkeysign/gtkui.py:185 +msgid "Open image..." +msgstr "" + +#: ../monkeysign/gtkui.py:186 +msgid "_Save QR code as..." +msgstr "" + +#: ../monkeysign/gtkui.py:187 +msgid "_Print QR code..." +msgstr "" + +#: ../monkeysign/gtkui.py:189 +msgid "Copy image to clipboard" +msgstr "" + +#: ../monkeysign/gtkui.py:189 +msgid "_Copy QR code" +msgstr "" + +#: ../monkeysign/gtkui.py:190 +msgid "Choose identity" +msgstr "" + +#: ../monkeysign/gtkui.py:190 +msgid "Identity" +msgstr "" + +#: ../monkeysign/gtkui.py:191 +msgid "Select video device to use" +msgstr "" + +#: ../monkeysign/gtkui.py:191 +msgid "Video device" +msgstr "" + +#: ../monkeysign/gtkui.py:192 +msgid "_Quit" +msgstr "" + +#: ../monkeysign/gtkui.py:201 +msgid "Disable video" +msgstr "" + +#: ../monkeysign/gtkui.py:245 +msgid "No video device detected." +msgstr "" + +#: ../monkeysign/gtkui.py:251 +msgid "" +"This is the output of your webcam, align a qrcode in the image to scan a " +"fingerprint." +msgstr "" + +#~ msgid "create the QR code display" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:269 +msgid "" +"This is a QR-code version of your PGP fingerprint. Scan this with another " +"monkeysign to transfer your fingerprint." +msgstr "" + +#~ msgid "list the secret keys for selection somewhere" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:291 ../monkeysign/gtkui.py:292 +msgid "Hide QR code" +msgstr "" + +#~ msgid "When window is resized, regenerate the QR code" +#~ msgstr "" + +#~ msgid "refresh the qrcode when the selected key changes" +#~ msgstr "" + +#~ msgid "draw the qrcode from the key fingerprint" +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked when a new video device is selected from the\n" +#~ " drop-down list. sets the new device for the zbar widget,\n" +#~ " which will eventually cause it to be opened and enabled\n" +#~ " " +#~ msgstr "" + +#~ msgid "Given a fingerprint, generate a QR code image with appropriate prefix" +#~ msgstr "" + +#~ msgid "Use a file chooser dialog to import an image containing a QR code" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:361 +msgid "cannot find signature for image file" +msgstr "" + +#: ../monkeysign/gtkui.py:363 +#, python-format +msgid "" +"The image provided cannot be verified using a trusted OpenPGP signature.\n" +"\n" +"Make sure the image comes from a trusted source (e.g. your own camera, which " +"you have never left unsurveilled) before signing this!\n" +"\n" +"DO NOT SIGN UNTRUSTED FINGERPRINTS!\n" +"\n" +"To get rid of this warning, if you really trust this image, use the " +"following command to sign the file\n" +"\n" +" gpg -s --detach %s\n" +msgstr "" + +#: ../monkeysign/gtkui.py:365 +msgid "image signature verified successfully" +msgstr "" + +#: ../monkeysign/gtkui.py:370 +msgid "Scan an image for QR codes" +msgstr "" + +#: ../monkeysign/gtkui.py:403 +msgid "data found in image!" +msgstr "" + +#~ msgid "" +#~ "Use a file chooser dialog to enable user to save the current QR code as a " +#~ "PNG image file" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:410 ../monkeysign/gtkui.py:435 +msgid "" +"No identity selected. Select one from the identiy menu or generate a OpenPGP " +"key if none is available." +msgstr "" + +#: ../monkeysign/gtkui.py:414 +msgid "Save QR code" +msgstr "" + +#~ msgid "copy the qrcode to the clipboard" +#~ msgstr "" + +#~ msgid "handler for the print QR code menu" +#~ msgstr "" + +#~ msgid "actually print the qr code" +#~ msgstr "" + +#~ msgid "Utility function to convert a PIL image instance to Pixbuf" +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked for pulsating progressbar\n" +#~ " " +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked when gpg key download is finished\n" +#~ " " +#~ msgstr "" + +#: ../monkeysign/gtkui.py:478 +msgid "fetching finished" +msgstr "" + +#~ msgid "" +#~ "callback invoked when a barcode is decoded by the zbar widget.\n" +#~ " checks for an openpgp fingerprint\n" +#~ " " +#~ msgstr "" + +#~ msgid "process zbar-scanned data" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:523 +msgid "zbar captured a frame, looking for 40 character hexadecimal fingerprint" +msgstr "" + +#: ../monkeysign/gtkui.py:534 ../monkeysign/ui.py:229 +#, python-format +msgid "looking for key %s in your keyring" +msgstr "" + +#: ../monkeysign/gtkui.py:547 +msgid "Please wait" +msgstr "" + +#: ../monkeysign/gtkui.py:549 +msgid "Retrieving public key from server..." +msgstr "" + +#: ../monkeysign/gtkui.py:563 +#, python-format +msgid "data found in barcode does not match a OpenPGP fingerprint pattern: %s" +msgstr "" + +#~ msgid "restart capture" +#~ msgstr "" + +#~ msgid "close the application" +#~ msgstr "" + +#~ msgid "" +#~ "User interface abstraction for monkeysign.\n" +#~ "\n" +#~ " This aims to factor out a common pattern to sign keys that is used\n" +#~ " regardless of the UI used.\n" +#~ "\n" +#~ " This is mostly geared at console/text-based and X11 interfaces,\n" +#~ " but could also be ported to other interfaces (touch-screen/phone\n" +#~ " interfaces would be interesting).\n" +#~ "\n" +#~ " The actual process is in main(), which outlines what the\n" +#~ " subclasses of this should be doing.\n" +#~ "\n" +#~ " You should have a docstring in derived classes, as it will be\n" +#~ " added to the 'usage' output.\n" +#~ "\n" +#~ " You should also set the usage and epilog parameters, see\n" +#~ " parse_args().\n" +#~ " " +#~ msgstr "" + +#~ msgid "parse the commandline arguments" +#~ msgstr "" + +#: ../monkeysign/ui.py:74 +msgid "show version information and quit" +msgstr "" + +#: ../monkeysign/ui.py:76 +msgid "request debugging information from GPG engine (lots of garbage)" +msgstr "" + +#: ../monkeysign/ui.py:78 +msgid "explain what we do along the way" +msgstr "" + +#: ../monkeysign/ui.py:80 +msgid "do not actually do anything" +msgstr "" + +#: ../monkeysign/ui.py:81 +msgid "user id to sign the key with" +msgstr "" + +#: ../monkeysign/ui.py:82 +msgid "certification level to sign the key with" +msgstr "" + +#: ../monkeysign/ui.py:84 +msgid "import in normal keyring a local certification" +msgstr "" + +#: ../monkeysign/ui.py:86 +msgid "keyserver to fetch keys from" +msgstr "" + +#: ../monkeysign/ui.py:87 +msgid "" +"SMTP server to use, use a colon to specify the port number if non-standard" +msgstr "" + +#: ../monkeysign/ui.py:88 +msgid "username for the SMTP server (default: no user)" +msgstr "" + +#: ../monkeysign/ui.py:89 +msgid "" +"password for the SMTP server (default: prompted, if --smtpuser is specified)" +msgstr "" + +#: ../monkeysign/ui.py:91 +msgid "Do not send email at all. (Default is to use sendmail.)" +msgstr "" + +#: ../monkeysign/ui.py:93 +msgid "" +"Override destination email for testing (default is to use the first uid on " +"the key or send email to each uid chosen)" +msgstr "" + +#: ../monkeysign/ui.py:136 +msgid "Initializing UI" +msgstr "" + +#: ../monkeysign/ui.py:147 +#, python-format +msgid "deleting the temporary keyring %s" +msgstr "" + +#: ../monkeysign/ui.py:172 +msgid "copied your gpg.conf in temporary keyring" +msgstr "" + +#~ msgid "" +#~ "\n" +#~ " General process\n" +#~ " ===============\n" +#~ "\n" +#~ " 1. fetch the key into a temporary keyring\n" +#~ " 1.a) if allowed (@todo), from the keyservers\n" +#~ " 1.b) from the local keyring (@todo try that first?)\n" +#~ " 2. copy the signing key secrets into the keyring\n" +#~ " 3. for every user id (or all, if -a is specified)\n" +#~ " 3.1. sign the uid, using gpg-agent\n" +#~ " 3.2. export and encrypt the signature\n" +#~ " 3.3. mail the key to the user\n" +#~ " 3.4. optionnally (-l), create a local signature and import in\n" +#~ " local keyring\n" +#~ " 4. trash the temporary keyring\n" +#~ " " +#~ msgstr "" + +#~ msgid "show a message to the user and abort program" +#~ msgstr "" + +#~ msgid "" +#~ "display an warning message\n" +#~ "\n" +#~ "this should not interrupt the flow of the program, but must be visible to " +#~ "the user" +#~ msgstr "" + +#~ msgid "log an informational message if verbose" +#~ msgstr "" + +#~ msgid "default UI is not interactive, so we assume yes all the time" +#~ msgstr "" + +#~ msgid "find the key to be signed somewhere" +#~ msgstr "" + +#: ../monkeysign/ui.py:231 +msgid "key not in local keyring" +msgstr "" + +#: ../monkeysign/ui.py:234 +#, python-format +msgid "fetching key %s from keyservers" +msgstr "" + +#: ../monkeysign/ui.py:238 +msgid "please provide a keyid or fingerprint, uids are not supported yet" +msgstr "" + +#: ../monkeysign/ui.py:241 +#, python-format +msgid "could not find key %s in your keyring or keyservers" +msgstr "" + +#~ msgid "" +#~ "import secret keys (but only the public part) from your keyring\n" +#~ "\n" +#~ "we use --secret-keyring instead of copying the secret key material,\n" +#~ "but we still need the public part in the temporary keyring for this to\n" +#~ "work.\n" +#~ msgstr "" + +#: ../monkeysign/ui.py:250 +#, python-format +msgid "copying your private key to temporary keyring in %s" +msgstr "" + +#: ../monkeysign/ui.py:258 +#, python-format +msgid "found secret key: %s" +msgstr "" + +#: ../monkeysign/ui.py:264 +msgid "no default secret key found, abort!" +msgstr "" + +#: ../monkeysign/ui.py:265 +#, python-format +msgid "signing key chosen: %s" +msgstr "" + +#: ../monkeysign/ui.py:269 +msgid "could not find public key material, do you have a GPG key?" +msgstr "" + +#~ msgid "sign the key uids, as specified" +#~ msgstr "" + +#: ../monkeysign/ui.py:276 +#, python-format +msgid "found %d keys matching your request" +msgstr "" + +#: ../monkeysign/ui.py:279 +#, python-format +msgid "" +"Signing the following key\n" +"\n" +"%s\n" +"\n" +"Sign all identities? [y/N] " +msgstr "" + +#: ../monkeysign/ui.py:291 +msgid "Choose the identity to sign" +msgstr "" + +#: ../monkeysign/ui.py:293 +msgid "no identity chosen" +msgstr "" + +#: ../monkeysign/ui.py:300 +msgid "Really sign key? [y/N] " +msgstr "" + +#: ../monkeysign/ui.py:303 +msgid "key signing failed" +msgstr "" + +#: ../monkeysign/ui.py:307 +msgid "making a non-exportable signature" +msgstr "" + +#: ../monkeysign/ui.py:312 +msgid "" +"could not import public key back into public keyring, something is wrong" +msgstr "" + +#: ../monkeysign/ui.py:314 +msgid "local key signing failed" +msgstr "" + +#: ../monkeysign/ui.py:322 +msgid "no key signed, nothing to export" +msgstr "" + +#: ../monkeysign/ui.py:330 ../monkeysign/ui.py:337 +#, python-format +msgid "failed to create email: %s" +msgstr "" + +#: ../monkeysign/ui.py:354 +#, python-format +msgid "Error connecting to SMTP server %s: %s" +msgstr "" + +#: ../monkeysign/ui.py:356 +#, python-format +msgid "Unexpected SMTP server error while talking to %s, code: %s (%s)" +msgstr "" + +#: ../monkeysign/ui.py:360 +msgid "SMTP server does not support STARTTLS" +msgstr "" + +#: ../monkeysign/ui.py:361 +msgid "authentication credentials will be sent in clear text" +msgstr "" + +#: ../monkeysign/ui.py:364 +#, python-format +msgid "enter SMTP password for server %s: " +msgstr "" + +#: ../monkeysign/ui.py:368 +#, python-format +msgid "sent message through SMTP server %s to %s" +msgstr "" + +#: ../monkeysign/ui.py:374 +#, python-format +msgid "sent message through sendmail to %s" +msgstr "" + +#: ../monkeysign/ui.py:377 +#, python-format +msgid "" +"not sending email to %s, as requested, here's the email message:\n" +"\n" +"%s" +msgstr "" + +#~ msgid "" +#~ "email generator\n" +#~ "\n" +#~ "this is a factory, ie. a class generating an object that represents\n" +#~ "the email and when turned into a string, is the actual\n" +#~ "mail.\n" +#~ msgstr "" + +#: ../monkeysign/ui.py:392 +msgid "Your signed OpenPGP key" +msgstr "" + +#: ../monkeysign/ui.py:395 +msgid "" +"\n" +"Please find attached your signed PGP key. You can import the signed\n" +"key by running each through `gpg --import`.\n" +"\n" +"If you have multiple user ids, each signature was sent in a separate\n" +"email to each user id.\n" +"\n" +"Note that your key was not uploaded to any keyservers. If you want\n" +"this new signature to be available to others, please upload it\n" +"yourself. With GnuPG this can be done using:\n" +"\n" +" gpg --keyserver pool.sks-keyservers.net --send-key <keyid>\n" +"\n" +"Regards,\n" +msgstr "" + +#~ msgid "" +#~ "email constructor\n" +#~ "\n" +#~ "we expect to find the following arguments:\n" +#~ "\n" +#~ "keydata: the signed public key material\n" +#~ "keyfpr: the fingerprint of that public key\n" +#~ "recipient: the recipient to encrypt the mail to\n" +#~ "mailfrom: who the mail originates from\n" +#~ "mailto: who to send the mail to (usually similar to recipient, but can be " +#~ "used to specify specific keyids" +#~ msgstr "" + +#~ msgid "this will remove any UID not matching the 'recipient' set in the class" +#~ msgstr "" + +#~ msgid "" +#~ "\n" +#~ " a multipart/mixed message containing a plain-text message\n" +#~ " explaining what this is, and a second part containing PGP data\n" +#~ " " +#~ msgstr "" + +#: ../monkeysign/ui.py:494 +#, python-format +msgid "signed PGP Key %s, uid %s" +msgstr "" + +#: ../monkeysign/ui.py:507 +msgid "This is a multi-part message in PGP/MIME format..." +msgstr "" + +#~ msgid "A non-wrapping formatter for OptionParse." +#~ msgstr "" diff --git a/po/es.po b/po/es.po index 7ba060702702913ecd17b6f4a11667bd08c196b5..e77fdd207b363fd83c0462441c71bf54fd4eeb79 100644 --- a/po/es.po +++ b/po/es.po @@ -6,8 +6,8 @@ msgstr "" "Project-Id-Version: monkeysign2.x\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-08-14 23:21-0400\n" -"PO-Revision-Date: 2015-02-03 22:54+0200\n" -"Last-Translator: Gonzalo Exequiel Pedone <hipersayan.x@gmail.com>\n" +"PO-Revision-Date: 2017-09-24 12:04+0000\n" +"Last-Translator: Sylvain Lesage <severo@rednegra.net>\n" "Language-Team: Spanish " "<https://hosted.weblate.org/projects/monkeysphere/monkeysign/es/>\n" "Language: es\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 2.2-dev\n" +"X-Generator: Weblate 2.17-dev\n" #: ../monkeysign/cli.py:26 msgid "" @@ -294,21 +294,23 @@ msgstr "" #: ../monkeysign/gtkui.py:365 msgid "image signature verified successfully" -msgstr "" +msgstr "Firma de la imagen verificada exitosamente" #: ../monkeysign/gtkui.py:370 msgid "Scan an image for QR codes" -msgstr "" +msgstr "Escanear una imagen para códigos QR" #: ../monkeysign/gtkui.py:403 msgid "data found in image!" -msgstr "" +msgstr "¡datos encontrados en la imagen!" #: ../monkeysign/gtkui.py:410 ../monkeysign/gtkui.py:435 msgid "" "No identity selected. Select one from the identiy menu or generate a OpenPGP " "key if none is available." msgstr "" +"Ninguna identidad seleccionada. Elegir una en el menú de identidad, o " +"generar una clave OpenPGP si no hay ninguna disponible." #: ../monkeysign/gtkui.py:414 msgid "Save QR code" @@ -321,6 +323,8 @@ msgstr "el traer terminó" #: ../monkeysign/gtkui.py:523 msgid "zbar captured a frame, looking for 40 character hexadecimal fingerprint" msgstr "" +"zbar capturó una imagen, está buscando una huella de 40 caracteres " +"hexadecimales" #: ../monkeysign/gtkui.py:534 ../monkeysign/ui.py:229 #, python-format @@ -339,10 +343,12 @@ msgstr "Trayendo clave publico del servidor..." #, python-format msgid "data found in barcode does not match a OpenPGP fingerprint pattern: %s" msgstr "" +"los datos encontrados en el código de barras no corresponden a una huella " +"OpenPGP: %s" #: ../monkeysign/ui.py:74 msgid "show version information and quit" -msgstr "" +msgstr "mostrar la información relativa a la versión y salir" #: ../monkeysign/ui.py:76 msgid "request debugging information from GPG engine (lots of garbage)" @@ -361,9 +367,8 @@ msgid "user id to sign the key with" msgstr "id de usuario que firmará el clave" #: ../monkeysign/ui.py:82 -#, fuzzy msgid "certification level to sign the key with" -msgstr "id de usuario que firmará el clave" +msgstr "nivel de certificación con el cuál firmar la clave" # Some words I am not sure would be the normal way to express technically in spanish such as keyring=llavero?, or parse=analizar? #: ../monkeysign/ui.py:84 @@ -378,15 +383,19 @@ msgstr "servidor de claves, de donde se traerá los claves" msgid "" "SMTP server to use, use a colon to specify the port number if non-standard" msgstr "" +"Servidor SMTP a utilizar, colocar \":\" para especificar el puerto si no es " +"estándar" #: ../monkeysign/ui.py:88 msgid "username for the SMTP server (default: no user)" -msgstr "" +msgstr "usuario del servidor SMTP (por defecto: sin usuario)" #: ../monkeysign/ui.py:89 msgid "" "password for the SMTP server (default: prompted, if --smtpuser is specified)" msgstr "" +"contraseña para el servidor SMTP (por defecto: se solicitará mediante la " +"interfaz, si se utiliza la opción --smtpuser)" #: ../monkeysign/ui.py:91 msgid "Do not send email at all. (Default is to use sendmail.)" @@ -517,27 +526,28 @@ msgid "failed to create email: %s" msgstr "no se pudo crear email: %s" #: ../monkeysign/ui.py:354 -#, fuzzy, python-format +#, python-format msgid "Error connecting to SMTP server %s: %s" -msgstr "mandó mensaje por medio de servidor de SMTP %s para %s" +msgstr "Error al conectarse al servidor SMTP %s: %s" #: ../monkeysign/ui.py:356 #, python-format msgid "Unexpected SMTP server error while talking to %s, code: %s (%s)" msgstr "" +"Error inesperado del servidor SMTP al comunicarse con %s, código %s (%s)" #: ../monkeysign/ui.py:360 msgid "SMTP server does not support STARTTLS" -msgstr "" +msgstr "El servidor SMTP no soporta STARTTLS" #: ../monkeysign/ui.py:361 msgid "authentication credentials will be sent in clear text" -msgstr "" +msgstr "las credenciales de autenticación serán enviados en claro" #: ../monkeysign/ui.py:364 #, python-format msgid "enter SMTP password for server %s: " -msgstr "" +msgstr "ingresar la contraseña para el servidor SMTP %s: " #: ../monkeysign/ui.py:368 #, python-format @@ -565,7 +575,6 @@ msgid "Your signed OpenPGP key" msgstr "Tu firmado OpenPGP clave" #: ../monkeysign/ui.py:395 -#, fuzzy msgid "" "\n" "Please find attached your signed PGP key. You can import the signed\n" @@ -583,23 +592,25 @@ msgid "" "Regards,\n" msgstr "" "\n" -"Favor de buscar tu clave de PGP adjunto. Usted puede importar el clave\n" -"firmado por pasar cada uno por 'gpg --import'.\n" +"Puedes encontrar tu clave PGP firmada en el adjunto. La puedes importar " +"utilizando el comando 'gpg --import'.\n" "\n" -"Debes saber que tu clave no fue mandado a ningún servidor de claves. Si " -"usted\n" -"quisieras que tu firma sea disponible a los demás, favor de mandarlo\n" -" usted mismo. Con GnuPG esto puede estar hecho por usar:\n" +"Si manejas varios usuarios, cada clave firmada será enviada en un correo " +"electrónico dedicado.\n" "\n" -" gpg --keyserver pool.sks-keyservers.net --send-key " -"<identificador_de_ID>\n" +"Debes saber que tu clave no fue subida a ningún servidor de claves. Si " +"quieres que esta nueva firma este disponible para los demás, no te olvides " +"subir tu clave. Con GnuPG lo puedes hacer con:\n" "\n" -"Respeto,\n" +" gpg --keyserver pool.sks-keyservers.net --send-key <identificador_de_ID>" +"\n" +"\n" +"Cordialmente,\n" #: ../monkeysign/ui.py:494 #, python-format msgid "signed PGP Key %s, uid %s" -msgstr "" +msgstr "clave PGP firmada %s, UID %s" #: ../monkeysign/ui.py:507 msgid "This is a multi-part message in PGP/MIME format..." diff --git a/po/nb_NO.po b/po/nb_NO.po new file mode 100644 index 0000000000000000000000000000000000000000..ee900f61623682c1d62cdce2fefd257d5d8a6ceb --- /dev/null +++ b/po/nb_NO.po @@ -0,0 +1,789 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-08-14 23:21-0400\n" +"PO-Revision-Date: 2018-09-03 13:20+0000\n" +"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n" +"Language-Team: Norwegian Bokmål <https://hosted.weblate.org/projects/" +"monkeysphere/monkeysign/nb_NO/>\n" +"Language: nb_NO\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.2-dev\n" + +#: ../monkeysign/cli.py:26 +msgid "" +"sign a key in a safe fashion.\n" +"\n" +"This command signs a key based on the fingerprint or user id\n" +"specified on the commandline, encrypt the result and mail it to the\n" +"user. This leave the choice of publishing the certification to that\n" +"person and makes sure that person owns the identity signed.\n" +"\n" +"This program assumes you have gpg-agent configured to prompt for\n" +"passwords." +msgstr "" +"signer en nøkkel på en trygg måte.\n" +"\n" +"Denne kommandoen signerer en nøkkel basert på fingeravtrykk eller bruker-ID\n" +"angtt på kommandolinjen, krypterer resultater og sender det til brukeren\n" +"per e-post. Dette overlater valget om publisering av sertifikatet til den " +"personen\n" +"og forsikrer at vedkommende eier signert identitet.\n" +"\n" +"Dette programmet forventer at du har gpg-agent satt opp til spørring om\n" +"passord." + +#: ../monkeysign/cli.py:37 +msgid "%prog [options] <keyid>" +msgstr "%prog [valg] <keyid>" + +#: ../monkeysign/cli.py:38 +msgid "<keyid>: a GPG fingerprint or key id" +msgstr "<keyid>: Et GPG-fingeravtrykk eller en nøkkel-ID" + +#: ../monkeysign/cli.py:45 +msgid "wrong number of arguments, use -h for full help" +msgstr "feil antall argumenter, bruk -h for full hjelpetekst" + +#: ../monkeysign/cli.py:57 +#, python-format +msgid "reset GPG_TTY to %s" +msgstr "tilbakestill GPG_TTY til %s" + +#: ../monkeysign/cli.py:65 +#, python-format +msgid "" +"Preparing to sign with this key\n" +"\n" +"%s" +msgstr "" +"Forbereder signering med denne nøkkelen\n" +"\n" +"%s" + +#: ../monkeysign/cli.py:100 +#, python-format +msgid " (1-%d or full UID, control-c to abort): " +msgstr " (1-%d eller full UID, Ctrl+C for å avbryte): " + +#: ../monkeysign/cli.py:104 +msgid "invalid uid" +msgstr "ugyldig UID" + +#: ../monkeysign/gpg.py:209 +#, python-format +msgid "could not find pattern '%s' in input, last skipped '%s'" +msgstr "kunne ikke finne mønsteret \"%s\" i inndata, hoppet sist over \"%s\"" + +#: ../monkeysign/gpg.py:329 +#, python-format +msgid "verifying file %s failed: %s." +msgstr "bekrefter fil %s mislykket: %s." + +#: ../monkeysign/gpg.py:366 ../monkeysign/gpg.py:386 +#, python-format +msgid "unexpected GPG exit code in list-keys: %d" +msgstr "uventet GPG-avslutningskode i list-keys: %d" + +#: ../monkeysign/gpg.py:398 +#, python-format +msgid "encryption to %s failed: %s." +msgstr "kryptering til %s mislyktes: %s." + +#: ../monkeysign/gpg.py:409 +#, python-format +msgid "decryption failed: %s" +msgstr "dekryptering mislyktes: %s" + +#: ../monkeysign/gpg.py:471 ../monkeysign/gpg.py:473 +#, python-format +msgid "cannot sign: %s" +msgstr "kan ikke signere: %s" + +#: ../monkeysign/gpg.py:483 +msgid "you already signed that key" +msgstr "du har allerede signert den nøkkelen" + +#: ../monkeysign/gpg.py:486 ../monkeysign/gpg.py:519 +#, python-format +msgid "unable to open key for editing: %s" +msgstr "klarte ikke å åpne nøkkel for redigering: %s" + +#: ../monkeysign/gpg.py:494 +msgid "unable to prompt for passphrase, is gpg-agent running?" +msgstr "kunne ikke spørre om passord, kjører gpg-agent?" + +#: ../monkeysign/gpg.py:530 +msgid "key is expired, cannot sign" +msgstr "nøkkel utløpt, kan ikke signere" + +#: ../monkeysign/gpg.py:532 +#, python-format +msgid "cannot sign, unknown error from gpg: %s" +msgstr "kan ikke signere, ukjent feil fra gpg: %s" + +#: ../monkeysign/gpg.py:537 +msgid "password confirmation failed" +msgstr "passordbekreftelse mislyktes" + +#: ../monkeysign/gpg.py:708 +#, python-format +msgid "record type '%s' not implemented" +msgstr "registreringstypen \"%s\" er ikke implementert" + +#: ../monkeysign/gtkui.py:40 +msgid "" +"sign a key in a safe fashion using a webcam to scan for qr-codes\n" +"\n" +"This command will fire up a graphical interface and turn on the webcam\n" +"(if available) on this computer. It will also display a qr-code of\n" +"your main OpenPGP key.\n" +"\n" +"The webcam is used to capture an OpenPGP fingerprint represented as a\n" +"qrcode (or whatever the zbar library can parse) and then go through a\n" +"signing process.\n" +"\n" +"The signature is then encrypted and mailed to the user. This leave the\n" +"choice of publishing the certification to that person and makes sure\n" +"that person owns the identity signed.\n" +"\n" +"This program assumes you have gpg-agent configure to prompt for\n" +"passwords.\n" +msgstr "" +"signer en nøkkel på en trygg måte ved bruk av et vevkamera for å skanne " +"etter QR-koder\n" +"\n" +"Denne kommandoen setter igang et grafisk grensesnittet og skrur på " +"vevkameraet\n" +"på datamaskinen (hvis tilgjengelig). Den vil også vise en QR-kode av\n" +"din hoved-OpenPGP-nøkkel.\n" +"\n" +"Vevkameraet brukt til å fange opp OpenPGP-fingeravtrykket representert som " +"en\n" +"QR-kode (eller hva zbar-biblioteket kan tolke) og går så gjennom en " +"signeringsprosess.\n" +"\n" +"Signaturen krypteres så og e-postes til brukeren. Dette overlater\n" +"valget om publisering til den personen og forsikrer at vedkommende\n" +"eier signert identitet.\n" +"\n" +"Programmet forventer at du har gpg-agent satt opp for å spørre om passord.\n" + +#: ../monkeysign/gtkui.py:120 +msgid "okay, signing" +msgstr "okei, signerer" + +#: ../monkeysign/gtkui.py:123 +msgid "user denied signature" +msgstr "bruker avslo signatur" + +#: ../monkeysign/gtkui.py:152 +msgid "Monkeysign (scan)" +msgstr "Monkeysign (skann)" + +#: ../monkeysign/gtkui.py:184 +msgid "_File" +msgstr "_Fil" + +#: ../monkeysign/gtkui.py:185 +msgid "Open image..." +msgstr "Åpne bilde…" + +#: ../monkeysign/gtkui.py:186 +msgid "_Save QR code as..." +msgstr "_Lagre QR-kode som…" + +#: ../monkeysign/gtkui.py:187 +msgid "_Print QR code..." +msgstr "_Skriv ut QR-kode…" + +#: ../monkeysign/gtkui.py:189 +msgid "Copy image to clipboard" +msgstr "Kopier bilde til utklippstavle" + +#: ../monkeysign/gtkui.py:189 +msgid "_Copy QR code" +msgstr "_Kopier QR-kode" + +#: ../monkeysign/gtkui.py:190 +msgid "Choose identity" +msgstr "Velg identitet" + +#: ../monkeysign/gtkui.py:190 +msgid "Identity" +msgstr "Identitet" + +#: ../monkeysign/gtkui.py:191 +msgid "Select video device to use" +msgstr "Velg videoenhet å bruke" + +#: ../monkeysign/gtkui.py:191 +msgid "Video device" +msgstr "Videoenhet" + +#: ../monkeysign/gtkui.py:192 +msgid "_Quit" +msgstr "_Avslutt" + +#: ../monkeysign/gtkui.py:201 +msgid "Disable video" +msgstr "Skru av video" + +#: ../monkeysign/gtkui.py:245 +msgid "No video device detected." +msgstr "Ingen videoenhet oppdaget." + +#: ../monkeysign/gtkui.py:251 +msgid "" +"This is the output of your webcam, align a qrcode in the image to scan a " +"fingerprint." +msgstr "" +"Dette er videostrømmen fra vevkameraet ditt, hold en QR-kode midt i " +"bildefeltet for å skanne et fingeravtrykk." + +#~ msgid "create the QR code display" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:269 +msgid "" +"This is a QR-code version of your PGP fingerprint. Scan this with another " +"monkeysign to transfer your fingerprint." +msgstr "" +"Dette er en QR-kodeversjon av ditt PGP-fingeravtrykk. Skann dette med en " +"annen monkeysign for å overføre fingeravtrykket ditt." + +#~ msgid "list the secret keys for selection somewhere" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:291 ../monkeysign/gtkui.py:292 +msgid "Hide QR code" +msgstr "Skjul QR-kode" + +#~ msgid "When window is resized, regenerate the QR code" +#~ msgstr "" + +#~ msgid "refresh the qrcode when the selected key changes" +#~ msgstr "" + +#~ msgid "draw the qrcode from the key fingerprint" +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked when a new video device is selected from the\n" +#~ " drop-down list. sets the new device for the zbar widget,\n" +#~ " which will eventually cause it to be opened and enabled\n" +#~ " " +#~ msgstr "" + +#~ msgid "Given a fingerprint, generate a QR code image with appropriate prefix" +#~ msgstr "" + +#~ msgid "Use a file chooser dialog to import an image containing a QR code" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:361 +msgid "cannot find signature for image file" +msgstr "kan ikke finne signatur for bildefil" + +#: ../monkeysign/gtkui.py:363 +#, python-format +msgid "" +"The image provided cannot be verified using a trusted OpenPGP signature.\n" +"\n" +"Make sure the image comes from a trusted source (e.g. your own camera, which " +"you have never left unsurveilled) before signing this!\n" +"\n" +"DO NOT SIGN UNTRUSTED FINGERPRINTS!\n" +"\n" +"To get rid of this warning, if you really trust this image, use the " +"following command to sign the file\n" +"\n" +" gpg -s --detach %s\n" +msgstr "" +"Angitt bilde kan ikke bekreftet ved bruk av en bekreftet OpenPGP-signatur.\n" +"\n" +"Husk at bildet kommer fra en betrodd kilde (f.eks. ditt eget kamera, som du " +"alltid har holdt oppsikt med) for du signerer dette!\n" +"\n" +"IKKE SIGNER UBETRODDE FINGERAVTRYKK!\n" +"\n" +"For å fjerne denne advarselen, hvis du virkelig stoler på dette bildet, bruk " +"følgende kommando til å signere filen\n" +"\n" +" gpg -s --detach %s\n" + +#: ../monkeysign/gtkui.py:365 +msgid "image signature verified successfully" +msgstr "bildesignatur bekreftet" + +#: ../monkeysign/gtkui.py:370 +msgid "Scan an image for QR codes" +msgstr "Skann et bilde for QR-koder" + +#: ../monkeysign/gtkui.py:403 +msgid "data found in image!" +msgstr "data funnet i bilde!" + +#~ msgid "" +#~ "Use a file chooser dialog to enable user to save the current QR code as a " +#~ "PNG image file" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:410 ../monkeysign/gtkui.py:435 +msgid "" +"No identity selected. Select one from the identiy menu or generate a OpenPGP " +"key if none is available." +msgstr "" +"Ingen identitet valgt. Velg én fra identitetsmenyen eller generer en OpenPGP-" +"nøkkel hvis ingen er tilgjengelige." + +#: ../monkeysign/gtkui.py:414 +msgid "Save QR code" +msgstr "Lagre QR-kode" + +#~ msgid "copy the qrcode to the clipboard" +#~ msgstr "" + +#~ msgid "handler for the print QR code menu" +#~ msgstr "" + +#~ msgid "actually print the qr code" +#~ msgstr "" + +#~ msgid "Utility function to convert a PIL image instance to Pixbuf" +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked for pulsating progressbar\n" +#~ " " +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked when gpg key download is finished\n" +#~ " " +#~ msgstr "" + +#: ../monkeysign/gtkui.py:478 +msgid "fetching finished" +msgstr "innhenting fullført" + +#~ msgid "" +#~ "callback invoked when a barcode is decoded by the zbar widget.\n" +#~ " checks for an openpgp fingerprint\n" +#~ " " +#~ msgstr "" + +#~ msgid "process zbar-scanned data" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:523 +msgid "zbar captured a frame, looking for 40 character hexadecimal fingerprint" +msgstr "zbar fanget ramme, ser etter 50-tegns heksadesimalt fingeravtrykk" + +#: ../monkeysign/gtkui.py:534 ../monkeysign/ui.py:229 +#, python-format +msgid "looking for key %s in your keyring" +msgstr "leter etter nøkkelen %s i din nøkkelring" + +#: ../monkeysign/gtkui.py:547 +msgid "Please wait" +msgstr "Vent" + +#: ../monkeysign/gtkui.py:549 +msgid "Retrieving public key from server..." +msgstr "Henter offentlig nøkkel fra tjener…" + +#: ../monkeysign/gtkui.py:563 +#, python-format +msgid "data found in barcode does not match a OpenPGP fingerprint pattern: %s" +msgstr "" +"data funnet i strekkode samsvarer ikke med et OpenPGP-fingeravtrykksmønster: " +"%s" + +#~ msgid "restart capture" +#~ msgstr "" + +#~ msgid "close the application" +#~ msgstr "" + +#~ msgid "" +#~ "User interface abstraction for monkeysign.\n" +#~ "\n" +#~ " This aims to factor out a common pattern to sign keys that is used\n" +#~ " regardless of the UI used.\n" +#~ "\n" +#~ " This is mostly geared at console/text-based and X11 interfaces,\n" +#~ " but could also be ported to other interfaces (touch-screen/phone\n" +#~ " interfaces would be interesting).\n" +#~ "\n" +#~ " The actual process is in main(), which outlines what the\n" +#~ " subclasses of this should be doing.\n" +#~ "\n" +#~ " You should have a docstring in derived classes, as it will be\n" +#~ " added to the 'usage' output.\n" +#~ "\n" +#~ " You should also set the usage and epilog parameters, see\n" +#~ " parse_args().\n" +#~ " " +#~ msgstr "" + +#~ msgid "parse the commandline arguments" +#~ msgstr "" + +#: ../monkeysign/ui.py:74 +msgid "show version information and quit" +msgstr "vis versjonsinformasjon og avslutt" + +#: ../monkeysign/ui.py:76 +msgid "request debugging information from GPG engine (lots of garbage)" +msgstr "forespør feilrettingsinformasjon fra GPG-motor (mye søppel)" + +#: ../monkeysign/ui.py:78 +msgid "explain what we do along the way" +msgstr "forklar hva vi gjør på veien dit" + +#: ../monkeysign/ui.py:80 +msgid "do not actually do anything" +msgstr "ikke gjør noe" + +#: ../monkeysign/ui.py:81 +msgid "user id to sign the key with" +msgstr "bruker-ID å signere nøkkel med" + +#: ../monkeysign/ui.py:82 +msgid "certification level to sign the key with" +msgstr "sertifiseringsnivå å sigere nøkkel med" + +#: ../monkeysign/ui.py:84 +msgid "import in normal keyring a local certification" +msgstr "importer lokal sertifisering inn i normal nøkkelring" + +#: ../monkeysign/ui.py:86 +msgid "keyserver to fetch keys from" +msgstr "nøkkeltjener å hente nøkler fra" + +#: ../monkeysign/ui.py:87 +msgid "" +"SMTP server to use, use a colon to specify the port number if non-standard" +msgstr "" +"SMTP-tjener å bruke, bruk et kolon til å angi portnummer hvis annet enn " +"standard" + +#: ../monkeysign/ui.py:88 +msgid "username for the SMTP server (default: no user)" +msgstr "brukernavn for SMTP-tjener (forvalg: ingen bruker)" + +#: ../monkeysign/ui.py:89 +msgid "" +"password for the SMTP server (default: prompted, if --smtpuser is specified)" +msgstr "" +"passord for SMTP-tjeneren (forvalg: forespurt, hvis --smtpuser er angitt)" + +#: ../monkeysign/ui.py:91 +msgid "Do not send email at all. (Default is to use sendmail.)" +msgstr "Ikke send noe e-post. (Forvalget er å bruke sendmail.)" + +#: ../monkeysign/ui.py:93 +msgid "" +"Override destination email for testing (default is to use the first uid on " +"the key or send email to each uid chosen)" +msgstr "" +"Overskriv e-postmottaker i testøyemed (forvalget er å bruke første UID på " +"nøkkelen eller å sende e-post til hver valgte UID)" + +#: ../monkeysign/ui.py:136 +msgid "Initializing UI" +msgstr "Igangsetter grafisk grensesnitt" + +#: ../monkeysign/ui.py:147 +#, python-format +msgid "deleting the temporary keyring %s" +msgstr "sletter den midlertidige nøkkelringen %s" + +#: ../monkeysign/ui.py:172 +msgid "copied your gpg.conf in temporary keyring" +msgstr "kopierte din gpg.conf inn i midlertidig nøkkelring" + +#~ msgid "" +#~ "\n" +#~ " General process\n" +#~ " ===============\n" +#~ "\n" +#~ " 1. fetch the key into a temporary keyring\n" +#~ " 1.a) if allowed (@todo), from the keyservers\n" +#~ " 1.b) from the local keyring (@todo try that first?)\n" +#~ " 2. copy the signing key secrets into the keyring\n" +#~ " 3. for every user id (or all, if -a is specified)\n" +#~ " 3.1. sign the uid, using gpg-agent\n" +#~ " 3.2. export and encrypt the signature\n" +#~ " 3.3. mail the key to the user\n" +#~ " 3.4. optionnally (-l), create a local signature and import in\n" +#~ " local keyring\n" +#~ " 4. trash the temporary keyring\n" +#~ " " +#~ msgstr "" + +#~ msgid "show a message to the user and abort program" +#~ msgstr "" + +#~ msgid "" +#~ "display an warning message\n" +#~ "\n" +#~ "this should not interrupt the flow of the program, but must be visible to " +#~ "the user" +#~ msgstr "" + +#~ msgid "log an informational message if verbose" +#~ msgstr "" + +#~ msgid "default UI is not interactive, so we assume yes all the time" +#~ msgstr "" + +#~ msgid "find the key to be signed somewhere" +#~ msgstr "" + +#: ../monkeysign/ui.py:231 +msgid "key not in local keyring" +msgstr "nøkkelringen finnes ikke i lokalt nøkkelknippe" + +#: ../monkeysign/ui.py:234 +#, python-format +msgid "fetching key %s from keyservers" +msgstr "henter nøkkelen %s fra nøkkeltjenerne" + +#: ../monkeysign/ui.py:238 +msgid "please provide a keyid or fingerprint, uids are not supported yet" +msgstr "angi nøkkelID eller fingeravtrykk, UID er ikke støttet enda" + +#: ../monkeysign/ui.py:241 +#, python-format +msgid "could not find key %s in your keyring or keyservers" +msgstr "" +"kunne ikke finne nøkkelen %s i nøkkelringen din eller på noen nøkkeltjenere" + +#~ msgid "" +#~ "import secret keys (but only the public part) from your keyring\n" +#~ "\n" +#~ "we use --secret-keyring instead of copying the secret key material,\n" +#~ "but we still need the public part in the temporary keyring for this to\n" +#~ "work.\n" +#~ msgstr "" + +#: ../monkeysign/ui.py:250 +#, python-format +msgid "copying your private key to temporary keyring in %s" +msgstr "kopierer din private nøkkel til midlertidig nøkkelring i %s" + +#: ../monkeysign/ui.py:258 +#, python-format +msgid "found secret key: %s" +msgstr "fant hemmelig nøkkel: %s" + +#: ../monkeysign/ui.py:264 +msgid "no default secret key found, abort!" +msgstr "fant ingen forvalgt hemmelig nøkkel, avbryter." + +#: ../monkeysign/ui.py:265 +#, python-format +msgid "signing key chosen: %s" +msgstr "signeringsnøkkel valgt: %s" + +#: ../monkeysign/ui.py:269 +msgid "could not find public key material, do you have a GPG key?" +msgstr "kunne ikke finne offentlig nøkkelmateriale, har du en GPG-nøkkel?" + +#~ msgid "sign the key uids, as specified" +#~ msgstr "" + +#: ../monkeysign/ui.py:276 +#, python-format +msgid "found %d keys matching your request" +msgstr "fant %d nøkler som samsvarer med din forespørsel" + +#: ../monkeysign/ui.py:279 +#, python-format +msgid "" +"Signing the following key\n" +"\n" +"%s\n" +"\n" +"Sign all identities? [y/N] " +msgstr "" +"Signerer følgende nøkkel\n" +"\n" +"%s\n" +"\n" +"Signer alle identiteter? [y/N] " + +#: ../monkeysign/ui.py:291 +msgid "Choose the identity to sign" +msgstr "Velg identitet å signere" + +#: ../monkeysign/ui.py:293 +msgid "no identity chosen" +msgstr "ingen identitet valgt" + +#: ../monkeysign/ui.py:300 +msgid "Really sign key? [y/N] " +msgstr "Virkelig signer nøkkel? [y/N] " + +#: ../monkeysign/ui.py:303 +msgid "key signing failed" +msgstr "nøkkelsignering mislyktes" + +#: ../monkeysign/ui.py:307 +msgid "making a non-exportable signature" +msgstr "lager en ikke-eksporterbar signatur" + +#: ../monkeysign/ui.py:312 +msgid "" +"could not import public key back into public keyring, something is wrong" +msgstr "" +"kunne ikke importere offentlig nøkkel tilbake i offentlig nøkkelring, noe er " +"galt" + +#: ../monkeysign/ui.py:314 +msgid "local key signing failed" +msgstr "lokal nøkkelsignering mislyktes" + +#: ../monkeysign/ui.py:322 +msgid "no key signed, nothing to export" +msgstr "ingen nøkkel signert, ingenting å eksportere" + +#: ../monkeysign/ui.py:330 ../monkeysign/ui.py:337 +#, python-format +msgid "failed to create email: %s" +msgstr "klarte ikke å opprette e-post: %s" + +#: ../monkeysign/ui.py:354 +#, python-format +msgid "Error connecting to SMTP server %s: %s" +msgstr "Feil ved tilkobling til SMTP-tjener %s: %s" + +#: ../monkeysign/ui.py:356 +#, python-format +msgid "Unexpected SMTP server error while talking to %s, code: %s (%s)" +msgstr "Uventet SMTP-feil under kommunikasjon med %s, kode: %s (%s)" + +#: ../monkeysign/ui.py:360 +msgid "SMTP server does not support STARTTLS" +msgstr "SMTP-tjeneren støtter ikke STARTTLS" + +#: ../monkeysign/ui.py:361 +msgid "authentication credentials will be sent in clear text" +msgstr "autentiseringsidentitetsdetaljer vil bli sendt i klartekst" + +#: ../monkeysign/ui.py:364 +#, python-format +msgid "enter SMTP password for server %s: " +msgstr "skriv inn SMTP-passordet for tjeneren %s: " + +#: ../monkeysign/ui.py:368 +#, python-format +msgid "sent message through SMTP server %s to %s" +msgstr "sendte melding gjennom SMTP-tjener %s til %s" + +#: ../monkeysign/ui.py:374 +#, python-format +msgid "sent message through sendmail to %s" +msgstr "sendte melding gjennom sendmail til %s" + +#: ../monkeysign/ui.py:377 +#, python-format +msgid "" +"not sending email to %s, as requested, here's the email message:\n" +"\n" +"%s" +msgstr "" +"sender ikke e-post til %s, som forespurt, her er e-postmeldingen:\n" +"\n" +"%s" + +#~ msgid "" +#~ "email generator\n" +#~ "\n" +#~ "this is a factory, ie. a class generating an object that represents\n" +#~ "the email and when turned into a string, is the actual\n" +#~ "mail.\n" +#~ msgstr "" + +#: ../monkeysign/ui.py:392 +msgid "Your signed OpenPGP key" +msgstr "Din signerte OpenPGP-nøkkel" + +#: ../monkeysign/ui.py:395 +msgid "" +"\n" +"Please find attached your signed PGP key. You can import the signed\n" +"key by running each through `gpg --import`.\n" +"\n" +"If you have multiple user ids, each signature was sent in a separate\n" +"email to each user id.\n" +"\n" +"Note that your key was not uploaded to any keyservers. If you want\n" +"this new signature to be available to others, please upload it\n" +"yourself. With GnuPG this can be done using:\n" +"\n" +" gpg --keyserver pool.sks-keyservers.net --send-key <keyid>\n" +"\n" +"Regards,\n" +msgstr "" +"\n" +"Du vil finne din PGP-nøkkel vedlagt. Du kan importere den signerte\n" +"nøkkelen ved å kjøre gjennom `gpg --import`.\n" +"\n" +"Hvis du har flerfoldige bruker-IDer, vil hver signatur ha blitt sendt i " +"egen\n" +"e-post til hber bruker-ID.\n" +"\n" +"Merk at nøkkelen din ikke ble lastet opp til noen nøkkeltjenere. Hvis du " +"ønsker\n" +"at denne nye signaturen skal være tilgjengelig for andre, last den opp til\n" +"deg selv. Med GnuPG kan dette gjøres ved bruk av:\n" +"\n" +" gpg --keyserver pool.sks-keyservers.net --send-key <keyid>\n" +"\n" +"Hilsen,\n" + +#~ msgid "" +#~ "email constructor\n" +#~ "\n" +#~ "we expect to find the following arguments:\n" +#~ "\n" +#~ "keydata: the signed public key material\n" +#~ "keyfpr: the fingerprint of that public key\n" +#~ "recipient: the recipient to encrypt the mail to\n" +#~ "mailfrom: who the mail originates from\n" +#~ "mailto: who to send the mail to (usually similar to recipient, but can be " +#~ "used to specify specific keyids" +#~ msgstr "" + +#~ msgid "this will remove any UID not matching the 'recipient' set in the class" +#~ msgstr "" + +#~ msgid "" +#~ "\n" +#~ " a multipart/mixed message containing a plain-text message\n" +#~ " explaining what this is, and a second part containing PGP data\n" +#~ " " +#~ msgstr "" + +#: ../monkeysign/ui.py:494 +#, python-format +msgid "signed PGP Key %s, uid %s" +msgstr "signerte PGP-nøkkel %s, UID %s" + +#: ../monkeysign/ui.py:507 +msgid "This is a multi-part message in PGP/MIME format..." +msgstr "Dette er en flerdelt melding i PGP/MIME-format…" + +#~ msgid "A non-wrapping formatter for OptionParse." +#~ msgstr "" diff --git a/po/nl.po b/po/nl.po new file mode 100644 index 0000000000000000000000000000000000000000..8583bc00869fbb67eebc16cb2f42077d8e7d12f6 --- /dev/null +++ b/po/nl.po @@ -0,0 +1,754 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-08-14 23:21-0400\n" +"PO-Revision-Date: 2018-03-16 17:36+0000\n" +"Last-Translator: Frans de Jonge <fransdejonge+weblate.org@gmail.com>\n" +"Language-Team: Dutch <https://hosted.weblate.org/projects/monkeysphere/" +"monkeysign/nl/>\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 2.20-dev\n" + +#: ../monkeysign/cli.py:26 +msgid "" +"sign a key in a safe fashion.\n" +"\n" +"This command signs a key based on the fingerprint or user id\n" +"specified on the commandline, encrypt the result and mail it to the\n" +"user. This leave the choice of publishing the certification to that\n" +"person and makes sure that person owns the identity signed.\n" +"\n" +"This program assumes you have gpg-agent configured to prompt for\n" +"passwords." +msgstr "" +"onderteken een sleutel op een veilige manier.\n" +"\n" +"Deze opdracht ondertekent een sleutel gebaseerd op de vingerafdruk of de op " +"de\n" +"commandoregel opgegeven gebruikers-ID. Het resultaat wordt daarna " +"versleuteld en verstuurd\n" +"naar de gebruiker. Dit geeft u de keuze om het certificaat aan die persoon " +"te publiceren en\n" +"ervoor te zorgen dat die persoon ook de ondertekende identiteit bezit.\n" +"\n" +"Deze applicatie gaat er vanuit dat u een GPG-agent heeft geconfigureerd " +"zodat deze kan\n" +"vragen naar wachtwoorden." + +#: ../monkeysign/cli.py:37 +msgid "%prog [options] <keyid>" +msgstr "%prog [opties] <sleutelid>" + +#: ../monkeysign/cli.py:38 +msgid "<keyid>: a GPG fingerprint or key id" +msgstr "<sleutelid>: een GPG-vingerafdruk of sleutel-ID" + +#: ../monkeysign/cli.py:45 +msgid "wrong number of arguments, use -h for full help" +msgstr "onjuist aantal argumenten; gebruik -h voor hulp" + +#: ../monkeysign/cli.py:57 +#, python-format +msgid "reset GPG_TTY to %s" +msgstr "GPG_TTY herstellen naar %s" + +#: ../monkeysign/cli.py:65 +#, python-format +msgid "" +"Preparing to sign with this key\n" +"\n" +"%s" +msgstr "" +"Bezig met voorbereiden om te ondertekenen met deze sleutel\n" +"\n" +"%s" + +#: ../monkeysign/cli.py:100 +#, python-format +msgid " (1-%d or full UID, control-c to abort): " +msgstr " (1-%d of volledige UID, control-c om af te breken): " + +#: ../monkeysign/cli.py:104 +msgid "invalid uid" +msgstr "ongeldige uid" + +#: ../monkeysign/gpg.py:209 +#, python-format +msgid "could not find pattern '%s' in input, last skipped '%s'" +msgstr "" +"het patroon '%s' kan niet worden gevonden in de invoer, laatst overgeslagen " +"'%s'" + +#: ../monkeysign/gpg.py:329 +#, python-format +msgid "verifying file %s failed: %s." +msgstr "het verifiëren van %s is mislukt: %s." + +#: ../monkeysign/gpg.py:366 ../monkeysign/gpg.py:386 +#, python-format +msgid "unexpected GPG exit code in list-keys: %d" +msgstr "onverwachte GPG-afsluitcode in list-keys: %d" + +#: ../monkeysign/gpg.py:398 +#, python-format +msgid "encryption to %s failed: %s." +msgstr "het versleutelen naar %s is mislukt: %s." + +#: ../monkeysign/gpg.py:409 +#, python-format +msgid "decryption failed: %s" +msgstr "het ontsleutelen is mislukt: %s" + +#: ../monkeysign/gpg.py:471 ../monkeysign/gpg.py:473 +#, python-format +msgid "cannot sign: %s" +msgstr "ondertekenen is niet mogelijk: %s" + +#: ../monkeysign/gpg.py:483 +msgid "you already signed that key" +msgstr "u heeft deze sleutel al ondertekend" + +#: ../monkeysign/gpg.py:486 ../monkeysign/gpg.py:519 +#, python-format +msgid "unable to open key for editing: %s" +msgstr "het openen van de sleutel om deze te bewerken is mislukt: %s" + +#: ../monkeysign/gpg.py:494 +msgid "unable to prompt for passphrase, is gpg-agent running?" +msgstr "het vragen naar een wachtwoord is mislukt. draait gpg-agent?" + +#: ../monkeysign/gpg.py:530 +msgid "key is expired, cannot sign" +msgstr "sleutel is verlopen, ondertekenen is niet mogelijk" + +#: ../monkeysign/gpg.py:532 +#, python-format +msgid "cannot sign, unknown error from gpg: %s" +msgstr "ondertekenen is niet mogelijk, onbekende fout van gpg: %s" + +#: ../monkeysign/gpg.py:537 +msgid "password confirmation failed" +msgstr "wachtwoordbevestiging is mislukt" + +#: ../monkeysign/gpg.py:708 +#, python-format +msgid "record type '%s' not implemented" +msgstr "recordtype '%s' niet geïmplementeerd" + +#: ../monkeysign/gtkui.py:40 +msgid "" +"sign a key in a safe fashion using a webcam to scan for qr-codes\n" +"\n" +"This command will fire up a graphical interface and turn on the webcam\n" +"(if available) on this computer. It will also display a qr-code of\n" +"your main OpenPGP key.\n" +"\n" +"The webcam is used to capture an OpenPGP fingerprint represented as a\n" +"qrcode (or whatever the zbar library can parse) and then go through a\n" +"signing process.\n" +"\n" +"The signature is then encrypted and mailed to the user. This leave the\n" +"choice of publishing the certification to that person and makes sure\n" +"that person owns the identity signed.\n" +"\n" +"This program assumes you have gpg-agent configure to prompt for\n" +"passwords.\n" +msgstr "" +"onderteken een sleutel op een veilige manier met een webcam om qr-codes te " +"scannen.\n" +"\n" +"Deze opdracht zal een grafische interface starten en de webcam aanzetten\n" +"(indien beschikbaar) op deze computer. Het zal ook een qr-code van\n" +"uw hoofd-OpenPGP-sleutel weergeven.\n" +"\n" +"De webcam wordt gebruikt om een OpenPHP vingerafdruk\n" +"in de vorm van een qr-code vast te leggen (of een ander formaat\n" +"dat wordt ondersteund door de zbar-bibliotheek) om vervolgens\n" +"door een tekenproces te gaan.\n" +"\n" +"De handtekening wordt dan versleuteld en naar de gebruiker gemaild.\n" +"Dit laat de keuze om het certificaat te publiceren aan die persoon en\n" +"verzekert dat de persoon de ondertekende identiteit bezit.\n" +"\n" +"Deze applicatie gaat er vanuit dat u een GPG-agent heeft geconfigureerd " +"zodat deze kan\n" +"vragen naar wachtwoorden.\n" + +#: ../monkeysign/gtkui.py:120 +msgid "okay, signing" +msgstr "in orde, ondertekenen" + +#: ../monkeysign/gtkui.py:123 +msgid "user denied signature" +msgstr "gebruiker weigerde handtekening" + +#: ../monkeysign/gtkui.py:152 +msgid "Monkeysign (scan)" +msgstr "" + +#: ../monkeysign/gtkui.py:184 +msgid "_File" +msgstr "_Bestand" + +#: ../monkeysign/gtkui.py:185 +msgid "Open image..." +msgstr "Open afbeelding..." + +#: ../monkeysign/gtkui.py:186 +msgid "_Save QR code as..." +msgstr "QR-code _opslaan als..." + +#: ../monkeysign/gtkui.py:187 +msgid "_Print QR code..." +msgstr "QR-code _printen..." + +#: ../monkeysign/gtkui.py:189 +msgid "Copy image to clipboard" +msgstr "Afbeelding naar klembord kopiëren" + +#: ../monkeysign/gtkui.py:189 +msgid "_Copy QR code" +msgstr "QR-code _kopiëren" + +#: ../monkeysign/gtkui.py:190 +msgid "Choose identity" +msgstr "Identiteit kiezen" + +#: ../monkeysign/gtkui.py:190 +msgid "Identity" +msgstr "Identiteit" + +#: ../monkeysign/gtkui.py:191 +msgid "Select video device to use" +msgstr "Video-apparaat selecteren" + +#: ../monkeysign/gtkui.py:191 +msgid "Video device" +msgstr "Video-apparaat" + +#: ../monkeysign/gtkui.py:192 +msgid "_Quit" +msgstr "_Afsluiten" + +#: ../monkeysign/gtkui.py:201 +msgid "Disable video" +msgstr "Video uitschakelen" + +#: ../monkeysign/gtkui.py:245 +msgid "No video device detected." +msgstr "Geen video-apparaat gevonden." + +#: ../monkeysign/gtkui.py:251 +msgid "" +"This is the output of your webcam, align a qrcode in the image to scan a " +"fingerprint." +msgstr "" +"Dit is de uitvoer van uw webcam. Lijn een qr-code in de afbeelding uit om " +"een handtekening te scannen." + +#~ msgid "create the QR code display" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:269 +msgid "" +"This is a QR-code version of your PGP fingerprint. Scan this with another " +"monkeysign to transfer your fingerprint." +msgstr "" +"Dit is een qr-code versie van uw PHP-vingerafdruk. Scan dit met een andere " +"monkeysign om uw vingerafdruk door te geven." + +#~ msgid "list the secret keys for selection somewhere" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:291 ../monkeysign/gtkui.py:292 +msgid "Hide QR code" +msgstr "QR-code verbergen" + +#~ msgid "When window is resized, regenerate the QR code" +#~ msgstr "" + +#~ msgid "refresh the qrcode when the selected key changes" +#~ msgstr "" + +#~ msgid "draw the qrcode from the key fingerprint" +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked when a new video device is selected from the\n" +#~ " drop-down list. sets the new device for the zbar widget,\n" +#~ " which will eventually cause it to be opened and enabled\n" +#~ " " +#~ msgstr "" + +#~ msgid "Given a fingerprint, generate a QR code image with appropriate prefix" +#~ msgstr "" + +#~ msgid "Use a file chooser dialog to import an image containing a QR code" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:361 +msgid "cannot find signature for image file" +msgstr "kan geen handtekening vinden in afbeeldingsbestand" + +#: ../monkeysign/gtkui.py:363 +#, python-format +msgid "" +"The image provided cannot be verified using a trusted OpenPGP signature.\n" +"\n" +"Make sure the image comes from a trusted source (e.g. your own camera, which " +"you have never left unsurveilled) before signing this!\n" +"\n" +"DO NOT SIGN UNTRUSTED FINGERPRINTS!\n" +"\n" +"To get rid of this warning, if you really trust this image, use the " +"following command to sign the file\n" +"\n" +" gpg -s --detach %s\n" +msgstr "" + +#: ../monkeysign/gtkui.py:365 +msgid "image signature verified successfully" +msgstr "afbeeldingshandtekening succesvol gecontroleerd" + +#: ../monkeysign/gtkui.py:370 +msgid "Scan an image for QR codes" +msgstr "Scan een afbeelding voor qr-codes" + +#: ../monkeysign/gtkui.py:403 +msgid "data found in image!" +msgstr "data gevonden in afbeelding!" + +#~ msgid "" +#~ "Use a file chooser dialog to enable user to save the current QR code as a " +#~ "PNG image file" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:410 ../monkeysign/gtkui.py:435 +msgid "" +"No identity selected. Select one from the identiy menu or generate a OpenPGP " +"key if none is available." +msgstr "" +"Geen identiteit geselecteerd. Selecteer er een in het identiteitsmenu of " +"genereer een OpenPGP-sleutel als er geen enkele beschikbaar is." + +#: ../monkeysign/gtkui.py:414 +msgid "Save QR code" +msgstr "Qr-code opslaan" + +#~ msgid "copy the qrcode to the clipboard" +#~ msgstr "" + +#~ msgid "handler for the print QR code menu" +#~ msgstr "" + +#~ msgid "actually print the qr code" +#~ msgstr "" + +#~ msgid "Utility function to convert a PIL image instance to Pixbuf" +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked for pulsating progressbar\n" +#~ " " +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked when gpg key download is finished\n" +#~ " " +#~ msgstr "" + +#: ../monkeysign/gtkui.py:478 +msgid "fetching finished" +msgstr "ophalen voltooid" + +#~ msgid "" +#~ "callback invoked when a barcode is decoded by the zbar widget.\n" +#~ " checks for an openpgp fingerprint\n" +#~ " " +#~ msgstr "" + +#~ msgid "process zbar-scanned data" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:523 +msgid "zbar captured a frame, looking for 40 character hexadecimal fingerprint" +msgstr "" +"zbar heeft een frame te pakken, op zoek naar een hexadecimale vingerafdruk " +"van 40 karakters" + +#: ../monkeysign/gtkui.py:534 ../monkeysign/ui.py:229 +#, python-format +msgid "looking for key %s in your keyring" +msgstr "zoeken naar sleutel %s in uw sleutelhanger" + +#: ../monkeysign/gtkui.py:547 +msgid "Please wait" +msgstr "Even geduld" + +#: ../monkeysign/gtkui.py:549 +msgid "Retrieving public key from server..." +msgstr "Publieke sleutel van server afhalen..." + +#: ../monkeysign/gtkui.py:563 +#, python-format +msgid "data found in barcode does not match a OpenPGP fingerprint pattern: %s" +msgstr "" +"data gevonden in barcode komt niet overeen met een OpenPGP-" +"vingerafdrukpatroom: %s" + +#~ msgid "restart capture" +#~ msgstr "" + +#~ msgid "close the application" +#~ msgstr "" + +#~ msgid "" +#~ "User interface abstraction for monkeysign.\n" +#~ "\n" +#~ " This aims to factor out a common pattern to sign keys that is used\n" +#~ " regardless of the UI used.\n" +#~ "\n" +#~ " This is mostly geared at console/text-based and X11 interfaces,\n" +#~ " but could also be ported to other interfaces (touch-screen/phone\n" +#~ " interfaces would be interesting).\n" +#~ "\n" +#~ " The actual process is in main(), which outlines what the\n" +#~ " subclasses of this should be doing.\n" +#~ "\n" +#~ " You should have a docstring in derived classes, as it will be\n" +#~ " added to the 'usage' output.\n" +#~ "\n" +#~ " You should also set the usage and epilog parameters, see\n" +#~ " parse_args().\n" +#~ " " +#~ msgstr "" + +#~ msgid "parse the commandline arguments" +#~ msgstr "" + +#: ../monkeysign/ui.py:74 +msgid "show version information and quit" +msgstr "toon versieinformatie en sluit af" + +#: ../monkeysign/ui.py:76 +msgid "request debugging information from GPG engine (lots of garbage)" +msgstr "" + +#: ../monkeysign/ui.py:78 +msgid "explain what we do along the way" +msgstr "leg uit wat we onderweg doen" + +#: ../monkeysign/ui.py:80 +msgid "do not actually do anything" +msgstr "doe eigenlijk niets" + +#: ../monkeysign/ui.py:81 +msgid "user id to sign the key with" +msgstr "" + +#: ../monkeysign/ui.py:82 +msgid "certification level to sign the key with" +msgstr "" + +#: ../monkeysign/ui.py:84 +msgid "import in normal keyring a local certification" +msgstr "lokale certificatie naar normale sleutelbox importeren" + +#: ../monkeysign/ui.py:86 +msgid "keyserver to fetch keys from" +msgstr "sleutelserver om sleutels van af te halen" + +#: ../monkeysign/ui.py:87 +msgid "" +"SMTP server to use, use a colon to specify the port number if non-standard" +msgstr "" + +#: ../monkeysign/ui.py:88 +msgid "username for the SMTP server (default: no user)" +msgstr "" + +#: ../monkeysign/ui.py:89 +msgid "" +"password for the SMTP server (default: prompted, if --smtpuser is specified)" +msgstr "" + +#: ../monkeysign/ui.py:91 +msgid "Do not send email at all. (Default is to use sendmail.)" +msgstr "" + +#: ../monkeysign/ui.py:93 +msgid "" +"Override destination email for testing (default is to use the first uid on " +"the key or send email to each uid chosen)" +msgstr "" + +#: ../monkeysign/ui.py:136 +msgid "Initializing UI" +msgstr "" + +#: ../monkeysign/ui.py:147 +#, python-format +msgid "deleting the temporary keyring %s" +msgstr "" + +#: ../monkeysign/ui.py:172 +msgid "copied your gpg.conf in temporary keyring" +msgstr "" + +#~ msgid "" +#~ "\n" +#~ " General process\n" +#~ " ===============\n" +#~ "\n" +#~ " 1. fetch the key into a temporary keyring\n" +#~ " 1.a) if allowed (@todo), from the keyservers\n" +#~ " 1.b) from the local keyring (@todo try that first?)\n" +#~ " 2. copy the signing key secrets into the keyring\n" +#~ " 3. for every user id (or all, if -a is specified)\n" +#~ " 3.1. sign the uid, using gpg-agent\n" +#~ " 3.2. export and encrypt the signature\n" +#~ " 3.3. mail the key to the user\n" +#~ " 3.4. optionnally (-l), create a local signature and import in\n" +#~ " local keyring\n" +#~ " 4. trash the temporary keyring\n" +#~ " " +#~ msgstr "" + +#~ msgid "show a message to the user and abort program" +#~ msgstr "" + +#~ msgid "" +#~ "display an warning message\n" +#~ "\n" +#~ "this should not interrupt the flow of the program, but must be visible to " +#~ "the user" +#~ msgstr "" + +#~ msgid "log an informational message if verbose" +#~ msgstr "" + +#~ msgid "default UI is not interactive, so we assume yes all the time" +#~ msgstr "" + +#~ msgid "find the key to be signed somewhere" +#~ msgstr "" + +#: ../monkeysign/ui.py:231 +msgid "key not in local keyring" +msgstr "" + +#: ../monkeysign/ui.py:234 +#, python-format +msgid "fetching key %s from keyservers" +msgstr "" + +#: ../monkeysign/ui.py:238 +msgid "please provide a keyid or fingerprint, uids are not supported yet" +msgstr "" + +#: ../monkeysign/ui.py:241 +#, python-format +msgid "could not find key %s in your keyring or keyservers" +msgstr "" + +#~ msgid "" +#~ "import secret keys (but only the public part) from your keyring\n" +#~ "\n" +#~ "we use --secret-keyring instead of copying the secret key material,\n" +#~ "but we still need the public part in the temporary keyring for this to\n" +#~ "work.\n" +#~ msgstr "" + +#: ../monkeysign/ui.py:250 +#, python-format +msgid "copying your private key to temporary keyring in %s" +msgstr "" + +#: ../monkeysign/ui.py:258 +#, python-format +msgid "found secret key: %s" +msgstr "" + +#: ../monkeysign/ui.py:264 +msgid "no default secret key found, abort!" +msgstr "" + +#: ../monkeysign/ui.py:265 +#, python-format +msgid "signing key chosen: %s" +msgstr "" + +#: ../monkeysign/ui.py:269 +msgid "could not find public key material, do you have a GPG key?" +msgstr "" + +#~ msgid "sign the key uids, as specified" +#~ msgstr "" + +#: ../monkeysign/ui.py:276 +#, python-format +msgid "found %d keys matching your request" +msgstr "" + +#: ../monkeysign/ui.py:279 +#, python-format +msgid "" +"Signing the following key\n" +"\n" +"%s\n" +"\n" +"Sign all identities? [y/N] " +msgstr "" + +#: ../monkeysign/ui.py:291 +msgid "Choose the identity to sign" +msgstr "" + +#: ../monkeysign/ui.py:293 +msgid "no identity chosen" +msgstr "" + +#: ../monkeysign/ui.py:300 +msgid "Really sign key? [y/N] " +msgstr "" + +#: ../monkeysign/ui.py:303 +msgid "key signing failed" +msgstr "" + +#: ../monkeysign/ui.py:307 +msgid "making a non-exportable signature" +msgstr "" + +#: ../monkeysign/ui.py:312 +msgid "" +"could not import public key back into public keyring, something is wrong" +msgstr "" + +#: ../monkeysign/ui.py:314 +msgid "local key signing failed" +msgstr "" + +#: ../monkeysign/ui.py:322 +msgid "no key signed, nothing to export" +msgstr "" + +#: ../monkeysign/ui.py:330 ../monkeysign/ui.py:337 +#, python-format +msgid "failed to create email: %s" +msgstr "" + +#: ../monkeysign/ui.py:354 +#, python-format +msgid "Error connecting to SMTP server %s: %s" +msgstr "" + +#: ../monkeysign/ui.py:356 +#, python-format +msgid "Unexpected SMTP server error while talking to %s, code: %s (%s)" +msgstr "" + +#: ../monkeysign/ui.py:360 +msgid "SMTP server does not support STARTTLS" +msgstr "" + +#: ../monkeysign/ui.py:361 +msgid "authentication credentials will be sent in clear text" +msgstr "" + +#: ../monkeysign/ui.py:364 +#, python-format +msgid "enter SMTP password for server %s: " +msgstr "" + +#: ../monkeysign/ui.py:368 +#, python-format +msgid "sent message through SMTP server %s to %s" +msgstr "" + +#: ../monkeysign/ui.py:374 +#, python-format +msgid "sent message through sendmail to %s" +msgstr "" + +#: ../monkeysign/ui.py:377 +#, python-format +msgid "" +"not sending email to %s, as requested, here's the email message:\n" +"\n" +"%s" +msgstr "" + +#~ msgid "" +#~ "email generator\n" +#~ "\n" +#~ "this is a factory, ie. a class generating an object that represents\n" +#~ "the email and when turned into a string, is the actual\n" +#~ "mail.\n" +#~ msgstr "" + +#: ../monkeysign/ui.py:392 +msgid "Your signed OpenPGP key" +msgstr "" + +#: ../monkeysign/ui.py:395 +msgid "" +"\n" +"Please find attached your signed PGP key. You can import the signed\n" +"key by running each through `gpg --import`.\n" +"\n" +"If you have multiple user ids, each signature was sent in a separate\n" +"email to each user id.\n" +"\n" +"Note that your key was not uploaded to any keyservers. If you want\n" +"this new signature to be available to others, please upload it\n" +"yourself. With GnuPG this can be done using:\n" +"\n" +" gpg --keyserver pool.sks-keyservers.net --send-key <keyid>\n" +"\n" +"Regards,\n" +msgstr "" + +#~ msgid "" +#~ "email constructor\n" +#~ "\n" +#~ "we expect to find the following arguments:\n" +#~ "\n" +#~ "keydata: the signed public key material\n" +#~ "keyfpr: the fingerprint of that public key\n" +#~ "recipient: the recipient to encrypt the mail to\n" +#~ "mailfrom: who the mail originates from\n" +#~ "mailto: who to send the mail to (usually similar to recipient, but can be " +#~ "used to specify specific keyids" +#~ msgstr "" + +#~ msgid "this will remove any UID not matching the 'recipient' set in the class" +#~ msgstr "" + +#~ msgid "" +#~ "\n" +#~ " a multipart/mixed message containing a plain-text message\n" +#~ " explaining what this is, and a second part containing PGP data\n" +#~ " " +#~ msgstr "" + +#: ../monkeysign/ui.py:494 +#, python-format +msgid "signed PGP Key %s, uid %s" +msgstr "" + +#: ../monkeysign/ui.py:507 +msgid "This is a multi-part message in PGP/MIME format..." +msgstr "Dit is een multi-part bericht in PHP/MIME formaat..." + +#~ msgid "A non-wrapping formatter for OptionParse." +#~ msgstr "" diff --git a/po/uk.po b/po/uk.po new file mode 100644 index 0000000000000000000000000000000000000000..6cb732d91a2128f84c306d9ab0c91fcb8099689c --- /dev/null +++ b/po/uk.po @@ -0,0 +1,708 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-08-14 23:21-0400\n" +"PO-Revision-Date: 2018-01-31 16:40+0000\n" +"Last-Translator: Марс Ямбар <mjambarmeta@gmail.com>\n" +"Language-Team: Ukrainian " +"<https://hosted.weblate.org/projects/monkeysphere/monkeysign/uk/>\n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=" +"4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 2.19-dev\n" + +#: ../monkeysign/cli.py:26 +msgid "" +"sign a key in a safe fashion.\n" +"\n" +"This command signs a key based on the fingerprint or user id\n" +"specified on the commandline, encrypt the result and mail it to the\n" +"user. This leave the choice of publishing the certification to that\n" +"person and makes sure that person owns the identity signed.\n" +"\n" +"This program assumes you have gpg-agent configured to prompt for\n" +"passwords." +msgstr "" + +#: ../monkeysign/cli.py:37 +msgid "%prog [options] <keyid>" +msgstr "%prog [опції] <keyid>" + +#: ../monkeysign/cli.py:38 +msgid "<keyid>: a GPG fingerprint or key id" +msgstr "" + +#: ../monkeysign/cli.py:45 +msgid "wrong number of arguments, use -h for full help" +msgstr "" + +#: ../monkeysign/cli.py:57 +#, python-format +msgid "reset GPG_TTY to %s" +msgstr "" + +#: ../monkeysign/cli.py:65 +#, python-format +msgid "" +"Preparing to sign with this key\n" +"\n" +"%s" +msgstr "" + +#: ../monkeysign/cli.py:100 +#, python-format +msgid " (1-%d or full UID, control-c to abort): " +msgstr "" + +#: ../monkeysign/cli.py:104 +msgid "invalid uid" +msgstr "" + +#: ../monkeysign/gpg.py:209 +#, python-format +msgid "could not find pattern '%s' in input, last skipped '%s'" +msgstr "" + +#: ../monkeysign/gpg.py:329 +#, python-format +msgid "verifying file %s failed: %s." +msgstr "" + +#: ../monkeysign/gpg.py:366 ../monkeysign/gpg.py:386 +#, python-format +msgid "unexpected GPG exit code in list-keys: %d" +msgstr "" + +#: ../monkeysign/gpg.py:398 +#, python-format +msgid "encryption to %s failed: %s." +msgstr "" + +#: ../monkeysign/gpg.py:409 +#, python-format +msgid "decryption failed: %s" +msgstr "" + +#: ../monkeysign/gpg.py:471 ../monkeysign/gpg.py:473 +#, python-format +msgid "cannot sign: %s" +msgstr "" + +#: ../monkeysign/gpg.py:483 +msgid "you already signed that key" +msgstr "" + +#: ../monkeysign/gpg.py:486 ../monkeysign/gpg.py:519 +#, python-format +msgid "unable to open key for editing: %s" +msgstr "" + +#: ../monkeysign/gpg.py:494 +msgid "unable to prompt for passphrase, is gpg-agent running?" +msgstr "" + +#: ../monkeysign/gpg.py:530 +msgid "key is expired, cannot sign" +msgstr "" + +#: ../monkeysign/gpg.py:532 +#, python-format +msgid "cannot sign, unknown error from gpg: %s" +msgstr "" + +#: ../monkeysign/gpg.py:537 +msgid "password confirmation failed" +msgstr "" + +#: ../monkeysign/gpg.py:708 +#, python-format +msgid "record type '%s' not implemented" +msgstr "" + +#: ../monkeysign/gtkui.py:40 +msgid "" +"sign a key in a safe fashion using a webcam to scan for qr-codes\n" +"\n" +"This command will fire up a graphical interface and turn on the webcam\n" +"(if available) on this computer. It will also display a qr-code of\n" +"your main OpenPGP key.\n" +"\n" +"The webcam is used to capture an OpenPGP fingerprint represented as a\n" +"qrcode (or whatever the zbar library can parse) and then go through a\n" +"signing process.\n" +"\n" +"The signature is then encrypted and mailed to the user. This leave the\n" +"choice of publishing the certification to that person and makes sure\n" +"that person owns the identity signed.\n" +"\n" +"This program assumes you have gpg-agent configure to prompt for\n" +"passwords.\n" +msgstr "" + +#: ../monkeysign/gtkui.py:120 +msgid "okay, signing" +msgstr "" + +#: ../monkeysign/gtkui.py:123 +msgid "user denied signature" +msgstr "" + +#: ../monkeysign/gtkui.py:152 +msgid "Monkeysign (scan)" +msgstr "" + +#: ../monkeysign/gtkui.py:184 +msgid "_File" +msgstr "" + +#: ../monkeysign/gtkui.py:185 +msgid "Open image..." +msgstr "" + +#: ../monkeysign/gtkui.py:186 +msgid "_Save QR code as..." +msgstr "" + +#: ../monkeysign/gtkui.py:187 +msgid "_Print QR code..." +msgstr "" + +#: ../monkeysign/gtkui.py:189 +msgid "Copy image to clipboard" +msgstr "" + +#: ../monkeysign/gtkui.py:189 +msgid "_Copy QR code" +msgstr "" + +#: ../monkeysign/gtkui.py:190 +msgid "Choose identity" +msgstr "" + +#: ../monkeysign/gtkui.py:190 +msgid "Identity" +msgstr "" + +#: ../monkeysign/gtkui.py:191 +msgid "Select video device to use" +msgstr "" + +#: ../monkeysign/gtkui.py:191 +msgid "Video device" +msgstr "" + +#: ../monkeysign/gtkui.py:192 +msgid "_Quit" +msgstr "" + +#: ../monkeysign/gtkui.py:201 +msgid "Disable video" +msgstr "" + +#: ../monkeysign/gtkui.py:245 +msgid "No video device detected." +msgstr "" + +#: ../monkeysign/gtkui.py:251 +msgid "" +"This is the output of your webcam, align a qrcode in the image to scan a " +"fingerprint." +msgstr "" + +#~ msgid "create the QR code display" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:269 +msgid "" +"This is a QR-code version of your PGP fingerprint. Scan this with another " +"monkeysign to transfer your fingerprint." +msgstr "" + +#~ msgid "list the secret keys for selection somewhere" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:291 ../monkeysign/gtkui.py:292 +msgid "Hide QR code" +msgstr "" + +#~ msgid "When window is resized, regenerate the QR code" +#~ msgstr "" + +#~ msgid "refresh the qrcode when the selected key changes" +#~ msgstr "" + +#~ msgid "draw the qrcode from the key fingerprint" +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked when a new video device is selected from the\n" +#~ " drop-down list. sets the new device for the zbar widget,\n" +#~ " which will eventually cause it to be opened and enabled\n" +#~ " " +#~ msgstr "" + +#~ msgid "Given a fingerprint, generate a QR code image with appropriate prefix" +#~ msgstr "" + +#~ msgid "Use a file chooser dialog to import an image containing a QR code" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:361 +msgid "cannot find signature for image file" +msgstr "" + +#: ../monkeysign/gtkui.py:363 +#, python-format +msgid "" +"The image provided cannot be verified using a trusted OpenPGP signature.\n" +"\n" +"Make sure the image comes from a trusted source (e.g. your own camera, which " +"you have never left unsurveilled) before signing this!\n" +"\n" +"DO NOT SIGN UNTRUSTED FINGERPRINTS!\n" +"\n" +"To get rid of this warning, if you really trust this image, use the " +"following command to sign the file\n" +"\n" +" gpg -s --detach %s\n" +msgstr "" + +#: ../monkeysign/gtkui.py:365 +msgid "image signature verified successfully" +msgstr "" + +#: ../monkeysign/gtkui.py:370 +msgid "Scan an image for QR codes" +msgstr "" + +#: ../monkeysign/gtkui.py:403 +msgid "data found in image!" +msgstr "" + +#~ msgid "" +#~ "Use a file chooser dialog to enable user to save the current QR code as a " +#~ "PNG image file" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:410 ../monkeysign/gtkui.py:435 +msgid "" +"No identity selected. Select one from the identiy menu or generate a OpenPGP " +"key if none is available." +msgstr "" + +#: ../monkeysign/gtkui.py:414 +msgid "Save QR code" +msgstr "" + +#~ msgid "copy the qrcode to the clipboard" +#~ msgstr "" + +#~ msgid "handler for the print QR code menu" +#~ msgstr "" + +#~ msgid "actually print the qr code" +#~ msgstr "" + +#~ msgid "Utility function to convert a PIL image instance to Pixbuf" +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked for pulsating progressbar\n" +#~ " " +#~ msgstr "" + +#~ msgid "" +#~ "callback invoked when gpg key download is finished\n" +#~ " " +#~ msgstr "" + +#: ../monkeysign/gtkui.py:478 +msgid "fetching finished" +msgstr "" + +#~ msgid "" +#~ "callback invoked when a barcode is decoded by the zbar widget.\n" +#~ " checks for an openpgp fingerprint\n" +#~ " " +#~ msgstr "" + +#~ msgid "process zbar-scanned data" +#~ msgstr "" + +#: ../monkeysign/gtkui.py:523 +msgid "zbar captured a frame, looking for 40 character hexadecimal fingerprint" +msgstr "" + +#: ../monkeysign/gtkui.py:534 ../monkeysign/ui.py:229 +#, python-format +msgid "looking for key %s in your keyring" +msgstr "" + +#: ../monkeysign/gtkui.py:547 +msgid "Please wait" +msgstr "" + +#: ../monkeysign/gtkui.py:549 +msgid "Retrieving public key from server..." +msgstr "" + +#: ../monkeysign/gtkui.py:563 +#, python-format +msgid "data found in barcode does not match a OpenPGP fingerprint pattern: %s" +msgstr "" + +#~ msgid "restart capture" +#~ msgstr "" + +#~ msgid "close the application" +#~ msgstr "" + +#~ msgid "" +#~ "User interface abstraction for monkeysign.\n" +#~ "\n" +#~ " This aims to factor out a common pattern to sign keys that is used\n" +#~ " regardless of the UI used.\n" +#~ "\n" +#~ " This is mostly geared at console/text-based and X11 interfaces,\n" +#~ " but could also be ported to other interfaces (touch-screen/phone\n" +#~ " interfaces would be interesting).\n" +#~ "\n" +#~ " The actual process is in main(), which outlines what the\n" +#~ " subclasses of this should be doing.\n" +#~ "\n" +#~ " You should have a docstring in derived classes, as it will be\n" +#~ " added to the 'usage' output.\n" +#~ "\n" +#~ " You should also set the usage and epilog parameters, see\n" +#~ " parse_args().\n" +#~ " " +#~ msgstr "" + +#~ msgid "parse the commandline arguments" +#~ msgstr "" + +#: ../monkeysign/ui.py:74 +msgid "show version information and quit" +msgstr "" + +#: ../monkeysign/ui.py:76 +msgid "request debugging information from GPG engine (lots of garbage)" +msgstr "" + +#: ../monkeysign/ui.py:78 +msgid "explain what we do along the way" +msgstr "" + +#: ../monkeysign/ui.py:80 +msgid "do not actually do anything" +msgstr "" + +#: ../monkeysign/ui.py:81 +msgid "user id to sign the key with" +msgstr "" + +#: ../monkeysign/ui.py:82 +msgid "certification level to sign the key with" +msgstr "" + +#: ../monkeysign/ui.py:84 +msgid "import in normal keyring a local certification" +msgstr "" + +#: ../monkeysign/ui.py:86 +msgid "keyserver to fetch keys from" +msgstr "" + +#: ../monkeysign/ui.py:87 +msgid "" +"SMTP server to use, use a colon to specify the port number if non-standard" +msgstr "" + +#: ../monkeysign/ui.py:88 +msgid "username for the SMTP server (default: no user)" +msgstr "" + +#: ../monkeysign/ui.py:89 +msgid "" +"password for the SMTP server (default: prompted, if --smtpuser is specified)" +msgstr "" + +#: ../monkeysign/ui.py:91 +msgid "Do not send email at all. (Default is to use sendmail.)" +msgstr "" + +#: ../monkeysign/ui.py:93 +msgid "" +"Override destination email for testing (default is to use the first uid on " +"the key or send email to each uid chosen)" +msgstr "" + +#: ../monkeysign/ui.py:136 +msgid "Initializing UI" +msgstr "" + +#: ../monkeysign/ui.py:147 +#, python-format +msgid "deleting the temporary keyring %s" +msgstr "" + +#: ../monkeysign/ui.py:172 +msgid "copied your gpg.conf in temporary keyring" +msgstr "" + +#~ msgid "" +#~ "\n" +#~ " General process\n" +#~ " ===============\n" +#~ "\n" +#~ " 1. fetch the key into a temporary keyring\n" +#~ " 1.a) if allowed (@todo), from the keyservers\n" +#~ " 1.b) from the local keyring (@todo try that first?)\n" +#~ " 2. copy the signing key secrets into the keyring\n" +#~ " 3. for every user id (or all, if -a is specified)\n" +#~ " 3.1. sign the uid, using gpg-agent\n" +#~ " 3.2. export and encrypt the signature\n" +#~ " 3.3. mail the key to the user\n" +#~ " 3.4. optionnally (-l), create a local signature and import in\n" +#~ " local keyring\n" +#~ " 4. trash the temporary keyring\n" +#~ " " +#~ msgstr "" + +#~ msgid "show a message to the user and abort program" +#~ msgstr "" + +#~ msgid "" +#~ "display an warning message\n" +#~ "\n" +#~ "this should not interrupt the flow of the program, but must be visible to " +#~ "the user" +#~ msgstr "" + +#~ msgid "log an informational message if verbose" +#~ msgstr "" + +#~ msgid "default UI is not interactive, so we assume yes all the time" +#~ msgstr "" + +#~ msgid "find the key to be signed somewhere" +#~ msgstr "" + +#: ../monkeysign/ui.py:231 +msgid "key not in local keyring" +msgstr "" + +#: ../monkeysign/ui.py:234 +#, python-format +msgid "fetching key %s from keyservers" +msgstr "" + +#: ../monkeysign/ui.py:238 +msgid "please provide a keyid or fingerprint, uids are not supported yet" +msgstr "" + +#: ../monkeysign/ui.py:241 +#, python-format +msgid "could not find key %s in your keyring or keyservers" +msgstr "" + +#~ msgid "" +#~ "import secret keys (but only the public part) from your keyring\n" +#~ "\n" +#~ "we use --secret-keyring instead of copying the secret key material,\n" +#~ "but we still need the public part in the temporary keyring for this to\n" +#~ "work.\n" +#~ msgstr "" + +#: ../monkeysign/ui.py:250 +#, python-format +msgid "copying your private key to temporary keyring in %s" +msgstr "" + +#: ../monkeysign/ui.py:258 +#, python-format +msgid "found secret key: %s" +msgstr "" + +#: ../monkeysign/ui.py:264 +msgid "no default secret key found, abort!" +msgstr "" + +#: ../monkeysign/ui.py:265 +#, python-format +msgid "signing key chosen: %s" +msgstr "" + +#: ../monkeysign/ui.py:269 +msgid "could not find public key material, do you have a GPG key?" +msgstr "" + +#~ msgid "sign the key uids, as specified" +#~ msgstr "" + +#: ../monkeysign/ui.py:276 +#, python-format +msgid "found %d keys matching your request" +msgstr "" + +#: ../monkeysign/ui.py:279 +#, python-format +msgid "" +"Signing the following key\n" +"\n" +"%s\n" +"\n" +"Sign all identities? [y/N] " +msgstr "" + +#: ../monkeysign/ui.py:291 +msgid "Choose the identity to sign" +msgstr "" + +#: ../monkeysign/ui.py:293 +msgid "no identity chosen" +msgstr "" + +#: ../monkeysign/ui.py:300 +msgid "Really sign key? [y/N] " +msgstr "" + +#: ../monkeysign/ui.py:303 +msgid "key signing failed" +msgstr "" + +#: ../monkeysign/ui.py:307 +msgid "making a non-exportable signature" +msgstr "" + +#: ../monkeysign/ui.py:312 +msgid "" +"could not import public key back into public keyring, something is wrong" +msgstr "" + +#: ../monkeysign/ui.py:314 +msgid "local key signing failed" +msgstr "" + +#: ../monkeysign/ui.py:322 +msgid "no key signed, nothing to export" +msgstr "" + +#: ../monkeysign/ui.py:330 ../monkeysign/ui.py:337 +#, python-format +msgid "failed to create email: %s" +msgstr "" + +#: ../monkeysign/ui.py:354 +#, python-format +msgid "Error connecting to SMTP server %s: %s" +msgstr "" + +#: ../monkeysign/ui.py:356 +#, python-format +msgid "Unexpected SMTP server error while talking to %s, code: %s (%s)" +msgstr "" + +#: ../monkeysign/ui.py:360 +msgid "SMTP server does not support STARTTLS" +msgstr "" + +#: ../monkeysign/ui.py:361 +msgid "authentication credentials will be sent in clear text" +msgstr "" + +#: ../monkeysign/ui.py:364 +#, python-format +msgid "enter SMTP password for server %s: " +msgstr "" + +#: ../monkeysign/ui.py:368 +#, python-format +msgid "sent message through SMTP server %s to %s" +msgstr "" + +#: ../monkeysign/ui.py:374 +#, python-format +msgid "sent message through sendmail to %s" +msgstr "" + +#: ../monkeysign/ui.py:377 +#, python-format +msgid "" +"not sending email to %s, as requested, here's the email message:\n" +"\n" +"%s" +msgstr "" + +#~ msgid "" +#~ "email generator\n" +#~ "\n" +#~ "this is a factory, ie. a class generating an object that represents\n" +#~ "the email and when turned into a string, is the actual\n" +#~ "mail.\n" +#~ msgstr "" + +#: ../monkeysign/ui.py:392 +msgid "Your signed OpenPGP key" +msgstr "" + +#: ../monkeysign/ui.py:395 +msgid "" +"\n" +"Please find attached your signed PGP key. You can import the signed\n" +"key by running each through `gpg --import`.\n" +"\n" +"If you have multiple user ids, each signature was sent in a separate\n" +"email to each user id.\n" +"\n" +"Note that your key was not uploaded to any keyservers. If you want\n" +"this new signature to be available to others, please upload it\n" +"yourself. With GnuPG this can be done using:\n" +"\n" +" gpg --keyserver pool.sks-keyservers.net --send-key <keyid>\n" +"\n" +"Regards,\n" +msgstr "" + +#~ msgid "" +#~ "email constructor\n" +#~ "\n" +#~ "we expect to find the following arguments:\n" +#~ "\n" +#~ "keydata: the signed public key material\n" +#~ "keyfpr: the fingerprint of that public key\n" +#~ "recipient: the recipient to encrypt the mail to\n" +#~ "mailfrom: who the mail originates from\n" +#~ "mailto: who to send the mail to (usually similar to recipient, but can be " +#~ "used to specify specific keyids" +#~ msgstr "" + +#~ msgid "this will remove any UID not matching the 'recipient' set in the class" +#~ msgstr "" + +#~ msgid "" +#~ "\n" +#~ " a multipart/mixed message containing a plain-text message\n" +#~ " explaining what this is, and a second part containing PGP data\n" +#~ " " +#~ msgstr "" + +#: ../monkeysign/ui.py:494 +#, python-format +msgid "signed PGP Key %s, uid %s" +msgstr "" + +#: ../monkeysign/ui.py:507 +msgid "This is a multi-part message in PGP/MIME format..." +msgstr "" + +#~ msgid "A non-wrapping formatter for OptionParse." +#~ msgstr "" diff --git a/setup.py b/setup.py index fdcc5dc81cbfdc51b623bdbdeee70d74421d5ddc..df25fd7e04bbd93a3202ee00a7cba78203580bc8 100755 --- a/setup.py +++ b/setup.py @@ -33,7 +33,8 @@ setup(name='monkeysign', use_scm_version={ 'write_to': 'monkeysign/_version.py', }, - setup_requires=['sphinx', 'setuptools_scm', 'pysocks'], + setup_requires=['sphinx', 'setuptools_scm'], + install_requires=['pysocks'], author='Antoine Beaupré', author_email='anarcat@debian.org', url=monkeysign.__website__, @@ -52,7 +53,7 @@ setup(name='monkeysign', ['doc/ui-mockups/logo.simple.svg']), ], classifiers=[ - 'Development Status :: 5 - Production', + 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'Intended Audience :: End Users/Desktop',