Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Théo Giovanna
bitmask_client
Commits
c6db8a1f
Unverified
Commit
c6db8a1f
authored
Apr 18, 2016
by
Kali Kaneko
Browse files
some fixes after review
parent
bfd8886e
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/leap/bitmask/core/configurable.py
View file @
c6db8a1f
...
...
@@ -18,15 +18,15 @@
Configurable Backend for Bitmask Service.
"""
import
ConfigParser
import
locale
import
os
import
re
import
sys
from
twisted.application
import
service
from
twisted.python
import
log
from
leap.common
import
files
from
leap.common.config
import
get_path_prefix
DEFAULT_BASEDIR
=
os
.
path
.
join
(
get_path_prefix
(),
'leap'
)
class
MissingConfigEntry
(
Exception
):
...
...
@@ -40,7 +40,7 @@ class ConfigurableService(service.MultiService):
config_file
=
u
"bitmaskd.cfg"
service_names
=
(
'mail'
,
'eip'
,
'zmq'
,
'web'
)
def
__init__
(
self
,
basedir
=
'~/.config/leap'
):
def
__init__
(
self
,
basedir
=
DEFAULT_BASEDIR
):
service
.
MultiService
.
__init__
(
self
)
path
=
os
.
path
.
abspath
(
os
.
path
.
expanduser
(
basedir
))
...
...
@@ -61,10 +61,9 @@ class ConfigurableService(service.MultiService):
except
(
ConfigParser
.
NoOptionError
,
ConfigParser
.
NoSectionError
):
if
default
is
None
:
fn
=
os
.
path
.
join
(
self
.
basedir
,
self
.
config_
file
)
fn
=
self
.
_get_
config_
path
(
)
raise
MissingConfigEntry
(
"%s is missing the [%s]%s entry"
%
(
_quote_output
(
fn
),
section
,
option
))
%
fn
,
section
,
option
)
return
default
def
set_config
(
self
,
section
,
option
,
value
):
...
...
@@ -82,12 +81,8 @@ class ConfigurableService(service.MultiService):
if
not
os
.
path
.
isfile
(
bitmaskd_cfg
):
self
.
_create_default_config
(
bitmaskd_cfg
)
try
:
with
open
(
bitmaskd_cfg
,
"rb"
)
as
f
:
self
.
config
.
readfp
(
f
)
except
EnvironmentError
:
if
os
.
path
.
exists
(
bitmaskd_cfg
):
raise
with
open
(
bitmaskd_cfg
,
"rb"
)
as
f
:
self
.
config
.
readfp
(
f
)
def
save_config
(
self
):
bitmaskd_cfg
=
self
.
_get_config_path
()
...
...
@@ -109,154 +104,3 @@ eip = True
zmq = True
web = False
"""
def
canonical_encoding
(
encoding
):
if
encoding
is
None
:
log
.
msg
(
"Warning: falling back to UTF-8 encoding."
,
level
=
log
.
WEIRD
)
encoding
=
'utf-8'
encoding
=
encoding
.
lower
()
if
encoding
==
"cp65001"
:
encoding
=
'utf-8'
elif
(
encoding
==
"us-ascii"
or
encoding
==
"646"
or
encoding
==
"ansi_x3.4-1968"
):
encoding
=
'ascii'
return
encoding
def
check_encoding
(
encoding
):
# sometimes Python returns an encoding name that it doesn't support for
# conversion fail early if this happens
try
:
u
"test"
.
encode
(
encoding
)
except
(
LookupError
,
AttributeError
):
raise
AssertionError
(
"The character encoding '%s' is not supported for conversion."
%
(
encoding
,))
filesystem_encoding
=
None
io_encoding
=
None
is_unicode_platform
=
False
def
_reload
():
global
filesystem_encoding
,
io_encoding
,
is_unicode_platform
filesystem_encoding
=
canonical_encoding
(
sys
.
getfilesystemencoding
())
check_encoding
(
filesystem_encoding
)
if
sys
.
platform
==
'win32'
:
# On Windows we install UTF-8 stream wrappers for sys.stdout and
# sys.stderr, and reencode the arguments as UTF-8 (see
# scripts/runner.py).
io_encoding
=
'utf-8'
else
:
ioenc
=
None
if
hasattr
(
sys
.
stdout
,
'encoding'
):
ioenc
=
sys
.
stdout
.
encoding
if
ioenc
is
None
:
try
:
ioenc
=
locale
.
getpreferredencoding
()
except
Exception
:
pass
# work around <http://bugs.python.org/issue1443504>
io_encoding
=
canonical_encoding
(
ioenc
)
check_encoding
(
io_encoding
)
is_unicode_platform
=
sys
.
platform
in
[
"win32"
,
"darwin"
]
_reload
()
def
_quote_output
(
s
,
quotemarks
=
True
,
quote_newlines
=
None
,
encoding
=
None
):
"""
Encode either a Unicode string or a UTF-8-encoded bytestring for
representation on stdout or stderr, tolerating errors. If 'quotemarks' is
True, the string is always quoted; otherwise, it is quoted only if
necessary to avoid ambiguity or control bytes in the output. (Newlines are
counted as control bytes iff quote_newlines is True.)
Quoting may use either single or double quotes. Within single quotes, all
characters stand for themselves, and ' will not appear. Within double
quotes, Python-compatible backslash escaping is used.
If not explicitly given, quote_newlines is True when quotemarks is True.
"""
assert
isinstance
(
s
,
(
str
,
unicode
))
if
quote_newlines
is
None
:
quote_newlines
=
quotemarks
if
isinstance
(
s
,
str
):
try
:
s
=
s
.
decode
(
'utf-8'
)
except
UnicodeDecodeError
:
return
'b"%s"'
%
(
ESCAPABLE_8BIT
.
sub
(
lambda
m
:
_str_escape
(
m
,
quote_newlines
),
s
),)
must_double_quote
=
(
quote_newlines
and
MUST_DOUBLE_QUOTE_NL
or
MUST_DOUBLE_QUOTE
)
if
must_double_quote
.
search
(
s
)
is
None
:
try
:
out
=
s
.
encode
(
encoding
or
io_encoding
)
if
quotemarks
or
out
.
startswith
(
'"'
):
return
"'%s'"
%
(
out
,)
else
:
return
out
except
(
UnicodeDecodeError
,
UnicodeEncodeError
):
pass
escaped
=
ESCAPABLE_UNICODE
.
sub
(
lambda
m
:
_unicode_escape
(
m
,
quote_newlines
),
s
)
return
'"%s"'
%
(
escaped
.
encode
(
encoding
or
io_encoding
,
'backslashreplace'
),)
def
_unicode_escape
(
m
,
quote_newlines
):
u
=
m
.
group
(
0
)
if
u
==
u
'"'
or
u
==
u
'$'
or
u
==
u
'`'
or
u
==
u
'
\\
'
:
return
u
'
\\
'
+
u
elif
u
==
u
'
\n
'
and
not
quote_newlines
:
return
u
if
len
(
u
)
==
2
:
codepoint
=
(
ord
(
u
[
0
])
-
0xD800
)
*
0x400
+
ord
(
u
[
1
])
-
0xDC00
+
0x10000
else
:
codepoint
=
ord
(
u
)
if
codepoint
>
0xFFFF
:
return
u
'
\\
U%08x'
%
(
codepoint
,)
elif
codepoint
>
0xFF
:
return
u
'
\\
u%04x'
%
(
codepoint
,)
else
:
return
u
'
\\
x%02x'
%
(
codepoint
,)
def
_str_escape
(
m
,
quote_newlines
):
c
=
m
.
group
(
0
)
if
c
==
'"'
or
c
==
'$'
or
c
==
'`'
or
c
==
'
\\
'
:
return
'
\\
'
+
c
elif
c
==
'
\n
'
and
not
quote_newlines
:
return
c
else
:
return
'
\\
x%02x'
%
(
ord
(
c
),)
MUST_DOUBLE_QUOTE_NL
=
re
.
compile
(
ur
'[^\x20-\x26\x28-\x7E\u00A0-\uD7FF\uE000-\uFDCF\uFDF0-\uFFFC]'
,
re
.
DOTALL
)
MUST_DOUBLE_QUOTE
=
re
.
compile
(
ur
'[^\n\x20-\x26\x28-\x7E\u00A0-\uD7FF\uE000-\uFDCF\uFDF0-\uFFFC]'
,
re
.
DOTALL
)
ESCAPABLE_8BIT
=
re
.
compile
(
r
'[^ !#\x25-\x5B\x5D-\x5F\x61-\x7E]'
,
re
.
DOTALL
)
# if we must double-quote, then we have to escape ", $ and `, but need not
# escape '
ESCAPABLE_UNICODE
=
re
.
compile
(
ur
'([\uD800-\uDBFF][\uDC00-\uDFFF])|'
# valid surrogate pairs
ur
'[^ !#\x25-\x5B\x5D-\x5F\x61-\x7E\u00A0-\uD7FF'
ur
'\uE000-\uFDCF\uFDF0-\uFFFC]'
,
re
.
DOTALL
)
src/leap/bitmask/core/dispatcher.py
View file @
c6db8a1f
...
...
@@ -84,6 +84,7 @@ class CommandDispatcher(object):
return
d
def
do_EIP
(
self
,
*
parts
):
subcmd
=
parts
[
1
]
eip_label
=
'eip'
...
...
src/leap/bitmask/core/mail_services.py
View file @
c6db8a1f
# -*- coding: utf-8 -*-
# mail_services.py
# Copyright (C) 2016 LEAP Encryption Acess Project
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Mail services.
...
...
@@ -6,7 +22,6 @@ This should be moved to the different packages when it stabilizes.
"""
import
json
import
os
from
glob
import
glob
from
collections
import
defaultdict
from
collections
import
namedtuple
...
...
@@ -26,31 +41,30 @@ from leap.mail.incoming.service import IncomingMail, INCOMING_CHECK_PERIOD
from
leap.mail
import
smtp
from
leap.bitmask.core.uuid_map
import
UserMap
from
leap.bitmask.core.configurable
import
DEFAULT_BASEDIR
class
Container
(
object
):
def
__init__
(
self
):
def
__init__
(
self
,
service
=
None
):
self
.
_instances
=
defaultdict
(
None
)
if
service
is
not
None
:
self
.
service
=
service
def
get_instance
(
self
,
key
):
return
self
.
_instances
.
get
(
key
,
None
)
def
add_instance
(
self
,
key
,
data
):
self
.
_instances
[
key
]
=
data
class
ImproperlyConfigured
(
Exception
):
pass
def
get_all_soledad_uuids
():
return
[
os
.
path
.
split
(
p
)[
-
1
].
split
(
'.db'
)[
0
]
for
p
in
glob
(
os
.
path
.
expanduser
(
'~/.config/leap/soledad/*.db'
))]
# FIXME do not hardcode basedir
class
SoledadContainer
(
Container
):
def
__init__
(
self
,
basedir
=
'~/.config/leap'
):
# FIXME do not hardcode basedir
def
__init__
(
self
,
basedir
=
DEFAULT_BASEDIR
):
self
.
_basedir
=
os
.
path
.
expanduser
(
basedir
)
self
.
_usermap
=
UserMap
()
super
(
SoledadContainer
,
self
).
__init__
()
...
...
@@ -75,19 +89,17 @@ class SoledadContainer(Container):
uuid
,
passphrase
,
soledad_path
,
soledad_url
,
cert_path
,
token
)
self
.
_instances
[
userid
]
=
soledad
self
.
add
_instances
(
userid
,
soledad
)
data
=
{
'user'
:
userid
,
'uuid'
:
uuid
,
'token'
:
token
,
'soledad'
:
soledad
}
self
.
service
.
trigger_hook
(
'on_new_soledad_instance'
,
**
data
)
def
_create_soledad_instance
(
self
,
uuid
,
passphrase
,
basedir
,
server_url
,
cert_file
,
token
):
def
_create_soledad_instance
(
self
,
uuid
,
passphrase
,
soledad_path
,
server_url
,
cert_file
,
token
):
# setup soledad info
secrets_path
=
os
.
path
.
join
(
basedir
,
'%s.secret'
%
uuid
)
local_db_path
=
os
.
path
.
join
(
basedir
,
'%s.db'
%
uuid
)
secrets_path
=
os
.
path
.
join
(
soledad_path
,
'%s.secret'
%
uuid
)
local_db_path
=
os
.
path
.
join
(
soledad_path
,
'%s.db'
%
uuid
)
if
token
is
None
:
syncable
=
False
...
...
@@ -143,8 +155,7 @@ class SoledadService(HookableService):
def
startService
(
self
):
log
.
msg
(
'Starting Soledad Service'
)
self
.
_container
=
SoledadContainer
()
self
.
_container
.
service
=
self
self
.
_container
=
SoledadContainer
(
service
=
self
)
super
(
SoledadService
,
self
).
startService
()
# hooks
...
...
@@ -209,7 +220,7 @@ class KeymanagerContainer(Container):
def
_on_keymanager_ready_cb
(
self
,
keymanager
,
userid
,
soledad
):
# TODO use onready-deferreds instead
self
.
_instance
s
[
userid
]
=
keymanager
self
.
add
_instance
(
userid
,
keymanager
)
log
.
msg
(
"Adding Keymanager instance for: %s"
%
userid
)
data
=
{
'userid'
:
userid
,
'soledad'
:
soledad
,
'keymanager'
:
keymanager
}
...
...
@@ -264,6 +275,11 @@ class KeymanagerContainer(Container):
token
=
self
.
service
.
tokens
.
get
(
userid
)
km_args
=
(
userid
,
nickserver_uri
,
soledad
)
# TODO use the method in
# services.soledadbootstrapper._get_gpg_bin_path.
# That should probably live in keymanager package.
km_kwargs
=
{
"token"
:
token
,
"uid"
:
uuid
,
"api_uri"
:
api_uri
,
"api_version"
:
"1"
,
...
...
@@ -373,10 +389,12 @@ class StandardMailService(service.MultiService, HookableService):
def
initializeChildrenServices
(
self
):
self
.
addService
(
IMAPService
(
self
.
_soledad_sessions
))
self
.
addService
(
IncomingMailService
(
self
))
self
.
addService
(
SMTPService
(
self
.
_soledad_sessions
,
self
.
_keymanager_sessions
,
self
.
_sendmail_opts
))
# TODO adapt the service to receive soledad/keymanager sessions object.
# See also the TODO before IncomingMailService.startInstance
self
.
addService
(
IncomingMailService
(
self
))
def
startService
(
self
):
log
.
msg
(
'Starting Mail Service...'
)
...
...
@@ -438,6 +456,7 @@ class StandardMailService(service.MultiService, HookableService):
if
not
active_user
:
return
defer
.
succeed
(
'NO ACTIVE USER'
)
token
=
self
.
_imap_tokens
.
get
(
active_user
)
# TODO return just the tuple, no format.
return
defer
.
succeed
(
"IMAP TOKEN (%s): %s"
%
(
active_user
,
token
))
def
get_smtp_token
(
self
):
...
...
@@ -445,6 +464,7 @@ class StandardMailService(service.MultiService, HookableService):
if
not
active_user
:
return
defer
.
succeed
(
'NO ACTIVE USER'
)
token
=
self
.
_smtp_tokens
.
get
(
active_user
)
# TODO return just the tuple, no format.
return
defer
.
succeed
(
"SMTP TOKEN (%s): %s"
%
(
active_user
,
token
))
def
do_get_smtp_cert_path
(
self
,
userid
):
...
...
@@ -560,7 +580,7 @@ class IncomingMailService(service.Service):
if
start_sync
:
incoming_instance
.
startService
()
acc
=
Account
(
soledad
)
acc
=
Account
(
soledad
,
userid
)
d
=
acc
.
callWhenReady
(
lambda
_
:
acc
.
get_collection_by_mailbox
(
INBOX_NAME
))
d
.
addCallback
(
setUpIncomingMail
)
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment