Merge lp:~diegosarmentero/ubuntu-sso-client/mac-port into lp:ubuntu-sso-client

Proposed by Diego Sarmentero
Status: Merged
Approved by: Diego Sarmentero
Approved revision: 955
Merged at revision: 952
Proposed branch: lp:~diegosarmentero/ubuntu-sso-client/mac-port
Merge into: lp:ubuntu-sso-client
Diff against target: 1655 lines (+825/-464)
25 files modified
data/qt/darwin.qss (+5/-0)
data/qt/resources.qrc (+1/-0)
run-mac-tests (+56/-0)
run-tests (+1/-1)
ubuntu_sso/keyring/__init__.py (+2/-6)
ubuntu_sso/keyring/linux.py (+0/-6)
ubuntu_sso/keyring/pykeyring.py (+2/-3)
ubuntu_sso/keyring/tests/test_pykeyring.py (+8/-9)
ubuntu_sso/main/__init__.py (+27/-1)
ubuntu_sso/main/darwin.py (+110/-0)
ubuntu_sso/main/perspective_broker.py (+352/-0)
ubuntu_sso/main/tests/test_darwin.py (+43/-0)
ubuntu_sso/main/tests/test_windows.py (+3/-1)
ubuntu_sso/main/windows.py (+23/-335)
ubuntu_sso/networkstate/__init__.py (+11/-11)
ubuntu_sso/networkstate/darwin.py (+95/-0)
ubuntu_sso/networkstate/linux.py (+7/-39)
ubuntu_sso/networkstate/networkstates.py (+51/-0)
ubuntu_sso/networkstate/tests/test_linux.py (+9/-10)
ubuntu_sso/qt/__init__.py (+7/-0)
ubuntu_sso/qt/main/__init__.py (+1/-1)
ubuntu_sso/utils/__init__.py (+9/-6)
ubuntu_sso/utils/linux.py (+0/-31)
ubuntu_sso/utils/qtwisted.py (+1/-3)
ubuntu_sso/utils/tests/test_qtwisted.py (+1/-1)
To merge this branch: bzr merge lp:~diegosarmentero/ubuntu-sso-client/mac-port
Reviewer Review Type Date Requested Status
Eric Casteleijn (community) Approve
Manuel de la Peña (community) Approve
Review via email: mp+103488@code.launchpad.net

Commit message

- Initial Branch for Mac Port (this comes from urbanape's branch).

To post a comment you must log in.
Revision history for this message
Manuel de la Peña (mandel) wrote :

I'm getting the following when running the run-mac-tests scripts in my machine:

./run-mac-tests: line 52: python_u1: command not found

Are there any steps I have to follow?

review: Needs Fixing
951. By Diego Sarmentero

merge

952. By Diego Sarmentero

Updating run mac tests script

953. By Diego Sarmentero

merge

954. By Diego Sarmentero

ignoring test_ipc

955. By Diego Sarmentero

run tests script doesn't setup the PATH, the env-mac script is required if we are using the buildout

Revision history for this message
Diego Sarmentero (diegosarmentero) wrote :

To run the tests of this branch you will need to download this branch:

bzr branch lp:~diegosarmentero/ubuntuone-windows-installer/mac-env

Execute the Buildout steps as are described in the GDoc.

Revision history for this message
Manuel de la Peña (mandel) :
review: Approve
Revision history for this message
Eric Casteleijn (thisfred) wrote :

Looks good to me.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'data/qt/darwin.qss'
--- data/qt/darwin.qss 1970-01-01 00:00:00 +0000
+++ data/qt/darwin.qss 2012-04-27 15:54:20 +0000
@@ -0,0 +1,5 @@
1/* Styles specific to the windows platform */
2
3QWidget {
4 font-family: "Ubuntu";
5}
06
=== modified file 'data/qt/resources.qrc'
--- data/qt/resources.qrc 2012-03-16 21:24:05 +0000
+++ data/qt/resources.qrc 2012-04-27 15:54:20 +0000
@@ -6,6 +6,7 @@
6 <file>../Ubuntu-B.ttf</file>6 <file>../Ubuntu-B.ttf</file>
7 <file>../balloon_shape.png</file>7 <file>../balloon_shape.png</file>
8 <file>stylesheet.qss</file>8 <file>stylesheet.qss</file>
9 <file>darwin.qss</file>
9 <file>windows.qss</file>10 <file>windows.qss</file>
10 <file>linux.qss</file>11 <file>linux.qss</file>
11 </qresource>12 </qresource>
1213
=== added file 'run-mac-tests'
--- run-mac-tests 1970-01-01 00:00:00 +0000
+++ run-mac-tests 2012-04-27 15:54:20 +0000
@@ -0,0 +1,56 @@
1#! /bin/bash
2#
3# Copyright 2010-2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# In addition, as a special exception, the copyright holders give
18# permission to link the code of portions of this program with the
19# OpenSSL library under certain conditions as described in each
20# individual source file, and distribute linked combinations
21# including the two.
22# You must obey the GNU General Public License in all respects
23# for all of the code used other than OpenSSL. If you modify
24# file(s) with this exception, you may extend this exception to your
25# version of the file(s), but you are not obligated to do so. If you
26# do not wish to do so, delete this exception statement from your
27# version. If you delete this exception statement from all source
28# files in the program, then also delete it here.
29GTK_TESTS_PATH=ubuntu_sso/gtk/tests
30WINDOWS_TESTS=test_windows.py
31
32set -e
33if [ $# -ne 0 ]; then
34 # run specific module given by the caller
35 MODULE="$@"
36else
37 # run all tests, useful for tarmac and reviews
38 MODULE="ubuntu_sso"
39fi
40
41style_check() {
42 python $u1lint --ignore ubuntu_sso/qt/ui
43 if [ -x `which pep8` ]; then
44 pep8 --exclude '.svn,CVS,.bzr,.hg,.git,*_ui.py,*_rc.py' --repeat . bin/*
45 else
46 echo "Please install the 'pep8' package."
47 fi
48}
49
50echo "*** Running QT test suite for ""$MODULE"" ***"
51./setup.py build
52python $u1trial --reactor=qt4 --gui -p "$GTK_TESTS_PATH" -i "test_gui.py, test_linux.py, test_qt.py, test_windows.py, test_glib.py, test_txsecrets.py, test_ipc.py, test_tcpactivation.py" "$MODULE"
53rm -rf _trial_temp
54rm -rf build
55
56style_check
057
=== modified file 'run-tests'
--- run-tests 2012-04-09 17:38:24 +0000
+++ run-tests 2012-04-27 15:54:20 +0000
@@ -59,7 +59,7 @@
59fi59fi
6060
61echo "*** Running GTK test suite for ""$MODULE"" ***"61echo "*** Running GTK test suite for ""$MODULE"" ***"
62$XVFB_CMDLINE u1trial --reactor=gi --gui -p "$QT_TESTS_PATH" -i "test_windows.py,test_qt.py" "$MODULE"62$XVFB_CMDLINE u1trial --reactor=gi --gui -p "$QT_TESTS_PATH" -i "test_windows.py,test_qt.py,test_qtwisted.py,test_pykeyring.py" "$MODULE"
63rm -rf _trial_temp63rm -rf _trial_temp
6464
65# hack to avoid:65# hack to avoid:
6666
=== modified file 'ubuntu_sso/keyring/__init__.py'
--- ubuntu_sso/keyring/__init__.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/keyring/__init__.py 2012-04-27 15:54:20 +0000
@@ -1,8 +1,4 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2# Authors:
3# Andrew Higginson
4# Alejandro J. Cura <alecu@canonical.com>
5# Manuel de la Pena <manuel@canonical.com>
6#2#
7# Copyright 2011-2012 Canonical Ltd.3# Copyright 2011-2012 Canonical Ltd.
8#4#
@@ -104,8 +100,8 @@
104 returnValue(None)100 returnValue(None)
105101
106102
107if sys.platform == 'win32':103if sys.platform in ('win32', 'darwin'):
108 from ubuntu_sso.keyring.windows import Keyring104 from ubuntu_sso.keyring.pykeyring import Keyring
109else:105else:
110 from ubuntu_sso.keyring.linux import Keyring106 from ubuntu_sso.keyring.linux import Keyring
111107
112108
=== modified file 'ubuntu_sso/keyring/linux.py'
--- ubuntu_sso/keyring/linux.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/keyring/linux.py 2012-04-27 15:54:20 +0000
@@ -2,12 +2,6 @@
2#2#
3# Copyright (C) 2010-2012 Canonical3# Copyright (C) 2010-2012 Canonical
4#4#
5# Authors:
6# Andrew Higginson
7# Alejandro J. Cura <alecu@canonical.com>
8# Natalia B. Bidart <natalia.bidart@canonical.com>
9# Manuel de la Pena <manuel@canonical.com>
10#
11# This program is free software; you can redistribute it and/or modify it under5# This program is free software; you can redistribute it and/or modify it under
12# the terms of the GNU General Public License as published by the Free Software6# the terms of the GNU General Public License as published by the Free Software
13# Foundation; version 3.7# Foundation; version 3.
148
=== renamed file 'ubuntu_sso/keyring/windows.py' => 'ubuntu_sso/keyring/pykeyring.py'
--- ubuntu_sso/keyring/windows.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/keyring/pykeyring.py 2012-04-27 15:54:20 +0000
@@ -1,5 +1,4 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2# Author: Manuel de la Pena <manuel@canonical.com>
3#2#
4# Copyright 2011-2012 Canonical Ltd.3# Copyright 2011-2012 Canonical Ltd.
5#4#
@@ -27,11 +26,11 @@
27# do not wish to do so, delete this exception statement from your26# do not wish to do so, delete this exception statement from your
28# version. If you delete this exception statement from all source27# version. If you delete this exception statement from all source
29# files in the program, then also delete it here.28# files in the program, then also delete it here.
30"""Keyring implementation on Windows."""29"""Keyring implementation for Windows and Darwin."""
3130
32from json import loads, dumps31from json import loads, dumps
3332
34from ubuntu_sso.utils.windows import qtDeferToThread as deferToThread33from ubuntu_sso.utils.qtwisted import qtDeferToThread as deferToThread
3534
36USERNAME = 'ubuntu_sso'35USERNAME = 'ubuntu_sso'
3736
3837
=== renamed file 'ubuntu_sso/keyring/tests/test_windows.py' => 'ubuntu_sso/keyring/tests/test_pykeyring.py'
--- ubuntu_sso/keyring/tests/test_windows.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/keyring/tests/test_pykeyring.py 2012-04-27 15:54:20 +0000
@@ -1,5 +1,4 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2# Author: Manuel de la Pena <manuel@canonical.com>
3#2#
4# Copyright 2011-2012 Canonical Ltd.3# Copyright 2011-2012 Canonical Ltd.
5#4#
@@ -27,14 +26,14 @@
27# do not wish to do so, delete this exception statement from your26# do not wish to do so, delete this exception statement from your
28# version. If you delete this exception statement from all source27# version. If you delete this exception statement from all source
29# files in the program, then also delete it here.28# files in the program, then also delete it here.
30"""Test the windows keyring implementation."""29"""Test the pykeyring implementation."""
3130
32from json import dumps31from json import dumps
3332
34from twisted.internet import defer33from twisted.internet import defer
35from twisted.trial.unittest import TestCase34from twisted.trial.unittest import TestCase
3635
37from ubuntu_sso.keyring import windows36from ubuntu_sso.keyring import pykeyring
3837
3938
40class FakePyKeyring(object):39class FakePyKeyring(object):
@@ -71,24 +70,24 @@
71 return func(args)70 return func(args)
7271
7372
74class TestWindowsKeyring(TestCase):73class TestPyKeyring(TestCase):
75 """Test the windows keyring implementation."""74 """Test the pykeyring implementation."""
7675
77 @defer.inlineCallbacks76 @defer.inlineCallbacks
78 def setUp(self):77 def setUp(self):
79 """Setup tests."""78 """Setup tests."""
80 yield super(TestWindowsKeyring, self).setUp()79 yield super(TestPyKeyring, self).setUp()
81 self.app_name = 'app_name'80 self.app_name = 'app_name'
82 self.fake_keyring = FakePyKeyring()81 self.fake_keyring = FakePyKeyring()
83 self.keyring = windows.Keyring(self.fake_keyring)82 self.keyring = pykeyring.Keyring(self.fake_keyring)
84 self.fake_defer = FakeDefer()83 self.fake_defer = FakeDefer()
85 self.patch(windows, "deferToThread",84 self.patch(pykeyring, "deferToThread",
86 self.fake_defer.fake_defer_to_thread)85 self.fake_defer.fake_defer_to_thread)
8786
88 # pylint: disable=E110387 # pylint: disable=E1103
89 def test_set_credentials(self):88 def test_set_credentials(self):
90 """Test setting the credentials."""89 """Test setting the credentials."""
91 self.keyring = windows.Keyring(self.fake_keyring)90 self.keyring = pykeyring.Keyring(self.fake_keyring)
92 d = self.keyring.set_credentials(self.app_name, 'password')91 d = self.keyring.set_credentials(self.app_name, 'password')
93 self.assertEqual(d.data['set_password'],92 self.assertEqual(d.data['set_password'],
94 (('app_name', 'ubuntu_sso', '"password"'), ))93 (('app_name', 'ubuntu_sso', '"password"'), ))
9594
=== modified file 'ubuntu_sso/main/__init__.py'
--- ubuntu_sso/main/__init__.py 2012-04-10 10:43:48 +0000
+++ ubuntu_sso/main/__init__.py 2012-04-27 15:54:20 +0000
@@ -57,12 +57,38 @@
57logger = setup_logging("ubuntu_sso.main")57logger = setup_logging("ubuntu_sso.main")
58TIMEOUT_INTERVAL = 10000 # 10 seconds58TIMEOUT_INTERVAL = 10000 # 10 seconds
5959
60# pylint: disable=C0103, W070360# pylint: disable=C0103, W0703, W0621
6161
62if sys.platform == 'win32':62if sys.platform == 'win32':
63 from ubuntu_sso.main import windows63 from ubuntu_sso.main import windows
64 from ubuntu_sso.main.perspective_broker import (
65 timeout_func,
66 shutdown_func,
67 start_setup,
68 main as main_func,
69 )
70
64 source = windows71 source = windows
72 source.timeout_func = timeout_func
73 source.shutdown_func = shutdown_func
74 source.start_setup = start_setup
75 source.main = main_func
76
65 TIMEOUT_INTERVAL = 10000000000 # forever (hack)77 TIMEOUT_INTERVAL = 10000000000 # forever (hack)
78elif sys.platform == 'darwin':
79 from ubuntu_sso.main import darwin
80 from ubuntu_sso.main.perspective_broker import (
81 timeout_func,
82 shutdown_func,
83 start_setup,
84 main as main_func,
85 )
86
87 source = darwin
88 source.timeout_func = timeout_func
89 source.shutdown_func = shutdown_func
90 source.start_setup = start_setup
91 source.main = main_func
66else:92else:
67 from ubuntu_sso.main import linux93 from ubuntu_sso.main import linux
68 source = linux94 source = linux
6995
=== added file 'ubuntu_sso/main/darwin.py'
--- ubuntu_sso/main/darwin.py 1970-01-01 00:00:00 +0000
+++ ubuntu_sso/main/darwin.py 2012-04-27 15:54:20 +0000
@@ -0,0 +1,110 @@
1# -*- coding: utf-8 -*-
2#
3# Copyright 2009-2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16"""Main module implementation specific for darwin (OS X).
17
18This module should never import from the multiplatform one (main/__init__.py),
19but the other way around. Likewise, this module should *not* have any logic
20regarding error processing or decision making about when to send a given
21signal.
22
23Also, most of the logging is being made in the main module to avoid
24duplication between the different platform implementations.
25
26"""
27
28import os
29import os.path
30
31from twisted.internet import defer
32
33import ubuntu_sso
34from ubuntu_sso.logger import setup_logging
35from ubuntu_sso.utils.ipc import BaseClient
36from ubuntu_sso.main.perspective_broker import (
37 SSO_SERVICE_NAME,
38 SSOLoginClient,
39 CredentialsManagementClient,
40 UbuntuSSOProxyBase,
41 )
42
43# Invalid name for signals that are CamelCase
44# pylint: disable=C0103
45
46
47logger = setup_logging("ubuntu_sso.main.darwin")
48U1_REG_PATH = r'Software\Ubuntu One'
49SSO_INSTALL_PATH = 'SSOInstallPath'
50SSO_BASE_PB_PORT = 50000
51SSO_RESERVED_PORTS = 3000
52SSO_PORT_ALLOCATION_STEP = 3 # contiguous ports for sso, u1client, and u1cp
53
54
55def get_sso_pb_port():
56 """Compute the port the SSO service should run on per-user."""
57 uid_modulo = os.getuid() % SSO_RESERVED_PORTS
58 return SSO_BASE_PB_PORT + uid_modulo * SSO_PORT_ALLOCATION_STEP
59
60
61class UbuntuSSOProxy(UbuntuSSOProxyBase):
62 """Object that exposes the diff referenceable objects."""
63
64 name = SSO_SERVICE_NAME
65
66 @property
67 def port(self):
68 """Get the port on which the SSO pb is running."""
69 return get_sso_pb_port()
70
71 @property
72 def cmdline(self):
73 """Get the command line to activate an executable."""
74 # MAYBE: use special URI schemes to have LaunchServices handle
75 # running the app, instead of paths to scripts
76 # e.g. 'x-ubuntuone-syncdaemon', 'x-ubuntu-sso-login'
77 ubuntu_sso_pkg_dir = os.path.dirname(
78 os.path.dirname(ubuntu_sso.__file__))
79 ubuntu_sso_bin_dir = os.path.join(ubuntu_sso_pkg_dir, 'bin')
80 ubuntu_sso_bin = os.path.join(ubuntu_sso_bin_dir, self.name)
81 ubuntuone_client_bin_dir = os.path.join(ubuntu_sso_pkg_dir,
82 '../ubuntuone-client/bin')
83 ubuntuone_client_bin = os.path.join(ubuntuone_client_bin_dir,
84 self.name)
85 if os.path.exists(ubuntuone_client_bin):
86 return ubuntuone_client_bin
87 return ubuntu_sso_bin
88
89
90class UbuntuSSOClient(BaseClient):
91 """Base client that provides remote access to the sso API."""
92
93 name = SSO_SERVICE_NAME
94
95 clients = {
96 'sso_login': SSOLoginClient,
97 'cred_manager': CredentialsManagementClient,
98 }
99
100 service_name = UbuntuSSOProxy.name
101 service_port = UbuntuSSOProxy.port
102 service_cmdline = UbuntuSSOProxy.cmdline
103
104
105@defer.inlineCallbacks
106def get_sso_client():
107 """Get a client to access the SSO service."""
108 result = UbuntuSSOClient()
109 yield result.connect()
110 defer.returnValue(result)
0111
=== added file 'ubuntu_sso/main/perspective_broker.py'
--- ubuntu_sso/main/perspective_broker.py 1970-01-01 00:00:00 +0000
+++ ubuntu_sso/main/perspective_broker.py 2012-04-27 15:54:20 +0000
@@ -0,0 +1,352 @@
1# -*- coding: utf-8 -*-
2#
3# Copyright 2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16"""Generic SSO client using Twisted Perspective Broker.
17
18This module should never import from the multiplatform one (main/__init__.py),
19but the other way around. Likewise, this module should *not* have any logic
20regarding error processing or decision making about when to send a given
21signal.
22
23Also, most of the logging is being made in the main module to avoid
24duplication between the different platform implementations.
25
26"""
27
28from twisted.internet.task import LoopingCall
29from twisted.python.failure import Failure
30
31from ubuntu_sso.logger import setup_logging
32from ubuntu_sso.utils.ipc import (
33 BaseService,
34 RemoteClient,
35 RemoteService,
36 signal,
37)
38
39logger = setup_logging("ubuntu_sso.main.perspective_broker")
40SSO_SERVICE_NAME = "ubuntu-sso-client"
41
42# Invalid name for signals that are CamelCase
43# pylint: disable=C0103
44
45
46class SSOLoginProxy(RemoteService):
47 """Login thru the Single Sign On service."""
48
49 remote_calls = [
50 'generate_captcha',
51 'register_user',
52 'login',
53 'login_and_ping',
54 'validate_email',
55 'validate_email_and_ping',
56 'request_password_reset_token',
57 'set_new_password',
58 ]
59
60 def __init__(self, root, *args, **kwargs):
61 super(SSOLoginProxy, self).__init__(*args, **kwargs)
62 self.root = root
63
64 # generate_capcha signals
65 @signal
66 def CaptchaGenerated(self, app_name, result):
67 """Signal thrown after the captcha is generated."""
68
69 @signal
70 def CaptchaGenerationError(self, app_name, error):
71 """Signal thrown when there's a problem generating the captcha."""
72
73 def generate_captcha(self, app_name, filename):
74 """Call the matching method in the processor."""
75 self.root.sso_login.generate_captcha(app_name, filename)
76
77 # register_user signals
78 @signal
79 def UserRegistered(self, app_name, result):
80 """Signal thrown when the user is registered."""
81
82 @signal
83 def UserRegistrationError(self, app_name, error):
84 """Signal thrown when there's a problem registering the user."""
85
86 def register_user(self, app_name, email, password, name,
87 captcha_id, captcha_solution):
88 """Call the matching method in the processor."""
89 self.root.sso_login.register_user(app_name, email, password, name,
90 captcha_id, captcha_solution)
91
92 # login signals
93 @signal
94 def LoggedIn(self, app_name, result):
95 """Signal thrown when the user is logged in."""
96
97 @signal
98 def LoginError(self, app_name, error):
99 """Signal thrown when there is a problem in the login."""
100
101 @signal
102 def UserNotValidated(self, app_name, result):
103 """Signal thrown when the user is not validated."""
104
105 def login(self, app_name, email, password, ping_url=None):
106 """Call the matching method in the processor."""
107 self.root.sso_login.login(app_name, email, password, ping_url)
108
109 login_and_ping = login
110
111 # validate_email signals
112 @signal
113 def EmailValidated(self, app_name, result):
114 """Signal thrown after the email is validated."""
115
116 @signal
117 def EmailValidationError(self, app_name, error):
118 """Signal thrown when there's a problem validating the email."""
119
120 def validate_email(self, app_name, email, password, email_token,
121 ping_url=None):
122 """Call the matching method in the processor."""
123 self.root.sso_login.validate_email(app_name,
124 email, password, email_token, ping_url)
125
126 validate_email_and_ping = validate_email
127
128 # request_password_reset_token signals
129 @signal
130 def PasswordResetTokenSent(self, app_name, result):
131 """Signal thrown when the token is succesfully sent."""
132
133 @signal
134 def PasswordResetError(self, app_name, error):
135 """Signal thrown when there's a problem sending the token."""
136
137 def request_password_reset_token(self, app_name, email):
138 """Call the matching method in the processor."""
139 self.root.sso_login.request_password_reset_token(app_name, email)
140
141 # set_new_password signals
142 @signal
143 def PasswordChanged(self, app_name, result):
144 """Signal thrown when the token is succesfully sent."""
145
146 @signal
147 def PasswordChangeError(self, app_name, error):
148 """Signal thrown when there's a problem sending the token."""
149
150 def set_new_password(self, app_name, email, token, new_password):
151 """Call the matching method in the processor."""
152 self.root.sso_login.set_new_password(app_name,
153 email, token, new_password)
154
155
156class CredentialsManagementProxy(RemoteService):
157 """Object that manages credentials.
158
159 Every exposed method in this class requires one mandatory argument:
160
161 - 'app_name': the name of the application. Will be displayed in the
162 GUI header, plus it will be used to find/build/clear tokens.
163
164 And accepts another parameter named 'args', which is a dictionary that
165 can contain the following:
166
167 - 'help_text': an explanatory text for the end-users, will be
168 shown below the header. This is an optional free text field.
169
170 - 'ping_url': the url to open after successful token retrieval. If
171 defined, the email will be attached to the url and will be pinged
172 with a OAuth-signed request.
173
174 - 'tc_url': the link to the Terms and Conditions page. If defined,
175 the checkbox to agree to the terms will link to it.
176
177 - 'window_id': the id of the window which will be set as a parent
178 of the GUI. If not defined, no parent will be set.
179
180 """
181
182 remote_calls = [
183 'find_credentials',
184 'clear_credentials',
185 'store_credentials',
186 'register',
187 'login',
188 'login_email_password',
189 ]
190
191 def __init__(self, root, *args, **kwargs):
192 super(CredentialsManagementProxy, self).__init__(*args, **kwargs)
193 self.root = root
194
195 @signal
196 def AuthorizationDenied(self, app_name):
197 """Signal thrown when the user denies the authorization."""
198
199 @signal
200 def CredentialsFound(self, app_name, credentials):
201 """Signal thrown when the credentials are found."""
202
203 @signal
204 def CredentialsNotFound(self, app_name):
205 """Signal thrown when the credentials are not found."""
206
207 @signal
208 def CredentialsCleared(self, app_name):
209 """Signal thrown when the credentials were cleared."""
210
211 @signal
212 def CredentialsStored(self, app_name):
213 """Signal thrown when the credentials were cleared."""
214
215 @signal
216 def CredentialsError(self, app_name, error_dict):
217 """Signal thrown when there is a problem getting the credentials."""
218
219 def find_credentials(self, app_name, args):
220 """Look for the credentials for an application.
221
222 - 'app_name': the name of the application which credentials are
223 going to be removed.
224
225 - 'args' is a dictionary, currently not used.
226
227 """
228 self.root.cred_manager.find_credentials(app_name, args)
229
230 def clear_credentials(self, app_name, args):
231 """Clear the credentials for an application.
232
233 - 'app_name': the name of the application which credentials are
234 going to be removed.
235
236 - 'args' is a dictionary, currently not used.
237
238 """
239 self.root.cred_manager.clear_credentials(app_name, args)
240
241 def store_credentials(self, app_name, args):
242 """Store the token for an application.
243
244 - 'app_name': the name of the application which credentials are
245 going to be stored.
246
247 - 'args' is the dictionary holding the credentials. Needs to provide
248 the following mandatory keys: 'token', 'token_key', 'consumer_key',
249 'consumer_secret'.
250
251 """
252 self.root.cred_manager.store_credentials(app_name, args)
253
254 def register(self, app_name, args):
255 """Get credentials if found else prompt GUI to register."""
256 self.root.cred_manager.register(app_name, args)
257
258 def login(self, app_name, args):
259 """Get credentials if found else prompt GUI to login."""
260 self.root.cred_manager.login(app_name, args)
261
262 def login_email_password(self, app_name, args):
263 """Get credentials if found, else login using email and password.
264
265 - 'args' should contain at least the follwing keys: 'email' and
266 'password'. Those will be used to issue a new SSO token, which will be
267 returned trough the CredentialsFound signal.
268
269 """
270 self.root.cred_manager.login_email_password(app_name, args)
271
272
273class UbuntuSSOProxyBase(BaseService):
274 """Object that exposes the diff referenceable objects."""
275
276 services = {
277 'sso_login': SSOLoginProxy,
278 'cred_manager': CredentialsManagementProxy,
279 }
280
281 name = SSO_SERVICE_NAME
282
283
284# ============================== client classes ==============================
285
286
287class SSOLoginClient(RemoteClient):
288 """Client that can perform calls to the remote SSOLogin object."""
289
290 call_remote_functions = SSOLoginProxy.remote_calls
291 signal_handlers = [
292 'CaptchaGenerated',
293 'CaptchaGenerationError',
294 'UserRegistered',
295 'UserRegistrationError',
296 'LoggedIn',
297 'LoginError',
298 'UserNotValidated',
299 'EmailValidated',
300 'EmailValidationError',
301 'PasswordResetTokenSent',
302 'PasswordResetError',
303 'PasswordChanged',
304 'PasswordChangeError',
305 ]
306
307
308class CredentialsManagementClient(RemoteClient):
309 """Client that can perform calls to the remote CredManagement object."""
310
311 call_remote_functions = CredentialsManagementProxy.remote_calls
312 signal_handlers = [
313 'AuthorizationDenied',
314 'CredentialsFound',
315 'CredentialsNotFound',
316 'CredentialsCleared',
317 'CredentialsStored',
318 'CredentialsError',
319 ]
320
321
322def add_timeout(interval, callback, *args, **kwargs):
323 """Add a timeout callback as a task."""
324 time_out_task = LoopingCall(callback, *args, **kwargs)
325 time_out_task.start(interval / 1000, now=False)
326
327
328timeout_func = add_timeout
329start_setup = lambda *a, **kw: None
330
331# the reactor does have run and stop methods
332# pylint: disable=E1101
333
334
335def shutdown_func():
336 """Stop the reactor."""
337 from twisted.internet import reactor
338 reactor.stop()
339
340
341def finish_setup(result, loop):
342 """Stop the reactor if a failure ocurred."""
343 if isinstance(result, Failure):
344 shutdown_func()
345
346
347def main():
348 """Run the specific mainloop."""
349 from twisted.internet import reactor
350 reactor.run()
351
352# pylint: enable=E1101
0353
=== added file 'ubuntu_sso/main/tests/test_darwin.py'
--- ubuntu_sso/main/tests/test_darwin.py 1970-01-01 00:00:00 +0000
+++ ubuntu_sso/main/tests/test_darwin.py 2012-04-27 15:54:20 +0000
@@ -0,0 +1,43 @@
1# -*- coding: utf-8 -*-
2#
3# Copyright 2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16"""Darwin specific tests for the main module."""
17
18from ubuntu_sso.main import darwin
19from ubuntu_sso.tests import TestCase
20
21# because we are using twisted we have java like names C0103
22# pylint: disable=C0103
23
24MOCK_SSO_DARWIN_UID = 1001
25
26
27class MockOsGetuid(object):
28 """Mocked os.getuid to support reliable uid for test"""
29
30 def getuid(self):
31 """Return the same uid for tests"""
32 return MOCK_SSO_DARWIN_UID
33
34
35class DarwinTestCase(TestCase):
36 """Tests for module level misc functions"""
37
38 def test_get_sso_pb_port(self):
39 """Test the get_sso_pb_port function, by patching os.getuid"""
40 mock_os = MockOsGetuid()
41 self.patch(darwin, "os", mock_os)
42 expected_port = 53003
43 self.assertEqual(darwin.get_sso_pb_port(), expected_port)
044
=== modified file 'ubuntu_sso/main/tests/test_windows.py'
--- ubuntu_sso/main/tests/test_windows.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/main/tests/test_windows.py 2012-04-27 15:54:20 +0000
@@ -32,6 +32,7 @@
32from _winreg import REG_SZ32from _winreg import REG_SZ
3333
34from ubuntu_sso.main import windows34from ubuntu_sso.main import windows
35from ubuntu_sso.main import perspective_broker
35from ubuntu_sso.tests import TestCase36from ubuntu_sso.tests import TestCase
3637
37# because we are using twisted we have java like names C010338# because we are using twisted we have java like names C0103
@@ -110,5 +111,6 @@
110 sample_value = "test 123"111 sample_value = "test 123"
111 self.patch(windows, "OpenKey", lambda key, subkey: sample_value)112 self.patch(windows, "OpenKey", lambda key, subkey: sample_value)
112 self.patch(windows, "QueryValueEx", lambda key, v: (key, REG_SZ))113 self.patch(windows, "QueryValueEx", lambda key, v: (key, REG_SZ))
113 cmdline = windows.get_activation_cmdline(windows.SSO_SERVICE_NAME)114 cmdline = windows.get_activation_cmdline(
115 perspective_broker.SSO_SERVICE_NAME)
114 self.assertEqual(sample_value, cmdline)116 self.assertEqual(sample_value, cmdline)
115117
=== modified file 'ubuntu_sso/main/windows.py'
--- ubuntu_sso/main/windows.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/main/windows.py 2012-04-27 15:54:20 +0000
@@ -45,350 +45,71 @@
45# pylint: enable=F040145# pylint: enable=F0401
4646
47from twisted.internet import defer47from twisted.internet import defer
48from twisted.internet.task import LoopingCall
49from twisted.python.failure import Failure
5048
51from ubuntu_sso.logger import setup_logging49from ubuntu_sso.logger import setup_logging
52from ubuntu_sso.utils.ipc import (50from ubuntu_sso.utils.ipc import BaseClient
53 BaseClient,51from ubuntu_sso.main.perspective_broker import (
54 BaseService,52 SSO_SERVICE_NAME,
55 RemoteClient,53 SSOLoginClient,
56 RemoteService,54 CredentialsManagementClient,
57 signal,55 UbuntuSSOProxyBase,
58)56 )
59
60
61# Invalid name for signals that are CamelCase
62# pylint: disable=C0103
6357
6458
65logger = setup_logging("ubuntu_sso.main.windows")59logger = setup_logging("ubuntu_sso.main.windows")
66NAMED_PIPE_URL = '\\\\.\\pipe\\ubuntu_sso\\%s'
67U1_REG_PATH = r'Software\Ubuntu One'60U1_REG_PATH = r'Software\Ubuntu One'
68SSO_INSTALL_PATH = 'SSOInstallPath'61SSO_INSTALL_PATH = 'SSOInstallPath'
69SSO_BASE_PB_PORT = 5000062SSO_BASE_PB_PORT = 50000
70SSO_RESERVED_PORTS = 300063SSO_RESERVED_PORTS = 3000
71SSO_PORT_ALLOCATION_STEP = 3 # contiguous ports for sso, u1client, and u1cp64SSO_PORT_ALLOCATION_STEP = 3 # contiguous ports for sso, u1client, and u1cp
72SSO_SERVICE_NAME = "ubuntu-sso-client"
7365
7466
75def get_user_id():67def get_user_id():
76 """Find the numeric user id."""68 """Compute the user id of the currently running process."""
77 process_handle = win32process.GetCurrentProcess()69 process_handle = win32process.GetCurrentProcess()
78 token_handle = win32security.OpenProcessToken(process_handle,70 token_handle = win32security.OpenProcessToken(process_handle,
79 win32security.TOKEN_ALL_ACCESS)71 win32security.TOKEN_ALL_ACCESS)
80 user_sid = win32security.GetTokenInformation(token_handle,72 user_sid = win32security.GetTokenInformation(token_handle,
81 win32security.TokenUser)[0]73 win32security.TokenUser)[0]
82 sid_parts = str(user_sid).split("-")74 sid_parts = str(user_sid).split("-")
83 uid = int(sid_parts[-1])75 return int(sid_parts[-1])
84 return uid
8576
8677
87def get_sso_pb_port():78def get_sso_pb_port():
88 """Get the port on which the SSO pb is running."""79 """Compute the port the SSO service should run on per-user."""
89 uid = get_user_id()80 uid_modulo = get_user_id() % SSO_RESERVED_PORTS
90 uid_modulo = uid % SSO_RESERVED_PORTS81 return SSO_BASE_PB_PORT + uid_modulo * SSO_PORT_ALLOCATION_STEP
91 port = SSO_BASE_PB_PORT + uid_modulo * SSO_PORT_ALLOCATION_STEP82
92 return port83
9384def get_activation_cmdline(name):
9485 """Find the path to the executable callback."""
95def get_activation_cmdline(service_name):
96 """Get the command line to activate an executable."""
97 key = OpenKey(HKEY_LOCAL_MACHINE, U1_REG_PATH)86 key = OpenKey(HKEY_LOCAL_MACHINE, U1_REG_PATH)
98 # pylint: disable=W061287 # pylint: disable=W0612
99 value, registry_type = QueryValueEx(key, "path-" + service_name)88 value, registry_type = QueryValueEx(key, "path-" + name)
100 return value89 return value
10190
10291
103class SSOLoginProxy(RemoteService):92class UbuntuSSOProxy(UbuntuSSOProxyBase):
104 """Login thru the Single Sign On service."""
105
106 remote_calls = [
107 'generate_captcha',
108 'register_user',
109 'login',
110 'login_and_ping',
111 'validate_email',
112 'validate_email_and_ping',
113 'request_password_reset_token',
114 'set_new_password',
115 ]
116
117 def __init__(self, root, *args, **kwargs):
118 super(SSOLoginProxy, self).__init__(*args, **kwargs)
119 self.root = root
120
121 # generate_capcha signals
122 @signal
123 def CaptchaGenerated(self, app_name, result):
124 """Signal thrown after the captcha is generated."""
125
126 @signal
127 def CaptchaGenerationError(self, app_name, error):
128 """Signal thrown when there's a problem generating the captcha."""
129
130 def generate_captcha(self, app_name, filename):
131 """Call the matching method in the processor."""
132 self.root.sso_login.generate_captcha(app_name, filename)
133
134 # register_user signals
135 @signal
136 def UserRegistered(self, app_name, result):
137 """Signal thrown when the user is registered."""
138
139 @signal
140 def UserRegistrationError(self, app_name, error):
141 """Signal thrown when there's a problem registering the user."""
142
143 def register_user(self, app_name, email, password, name,
144 captcha_id, captcha_solution):
145 """Call the matching method in the processor."""
146 self.root.sso_login.register_user(app_name, email, password, name,
147 captcha_id, captcha_solution)
148
149 # login signals
150 @signal
151 def LoggedIn(self, app_name, result):
152 """Signal thrown when the user is logged in."""
153
154 @signal
155 def LoginError(self, app_name, error):
156 """Signal thrown when there is a problem in the login."""
157
158 @signal
159 def UserNotValidated(self, app_name, result):
160 """Signal thrown when the user is not validated."""
161
162 def login(self, app_name, email, password, ping_url=None):
163 """Call the matching method in the processor."""
164 self.root.sso_login.login(app_name, email, password, ping_url)
165
166 login_and_ping = login
167
168 # validate_email signals
169 @signal
170 def EmailValidated(self, app_name, result):
171 """Signal thrown after the email is validated."""
172
173 @signal
174 def EmailValidationError(self, app_name, error):
175 """Signal thrown when there's a problem validating the email."""
176
177 def validate_email(self, app_name, email, password, email_token,
178 ping_url=None):
179 """Call the matching method in the processor."""
180 self.root.sso_login.validate_email(app_name,
181 email, password, email_token, ping_url)
182
183 validate_email_and_ping = validate_email
184
185 # request_password_reset_token signals
186 @signal
187 def PasswordResetTokenSent(self, app_name, result):
188 """Signal thrown when the token is succesfully sent."""
189
190 @signal
191 def PasswordResetError(self, app_name, error):
192 """Signal thrown when there's a problem sending the token."""
193
194 def request_password_reset_token(self, app_name, email):
195 """Call the matching method in the processor."""
196 self.root.sso_login.request_password_reset_token(app_name, email)
197
198 # set_new_password signals
199 @signal
200 def PasswordChanged(self, app_name, result):
201 """Signal thrown when the token is succesfully sent."""
202
203 @signal
204 def PasswordChangeError(self, app_name, error):
205 """Signal thrown when there's a problem sending the token."""
206
207 def set_new_password(self, app_name, email, token, new_password):
208 """Call the matching method in the processor."""
209 self.root.sso_login.set_new_password(app_name,
210 email, token, new_password)
211
212
213class CredentialsManagementProxy(RemoteService):
214 """Object that manages credentials.
215
216 Every exposed method in this class requires one mandatory argument:
217
218 - 'app_name': the name of the application. Will be displayed in the
219 GUI header, plus it will be used to find/build/clear tokens.
220
221 And accepts another parameter named 'args', which is a dictionary that
222 can contain the following:
223
224 - 'help_text': an explanatory text for the end-users, will be
225 shown below the header. This is an optional free text field.
226
227 - 'ping_url': the url to open after successful token retrieval. If
228 defined, the email will be attached to the url and will be pinged
229 with a OAuth-signed request.
230
231 - 'tc_url': the link to the Terms and Conditions page. If defined,
232 the checkbox to agree to the terms will link to it.
233
234 - 'window_id': the id of the window which will be set as a parent
235 of the GUI. If not defined, no parent will be set.
236
237 """
238
239 remote_calls = [
240 'find_credentials',
241 'clear_credentials',
242 'store_credentials',
243 'register',
244 'login',
245 'login_email_password',
246 ]
247
248 def __init__(self, root, *args, **kwargs):
249 super(CredentialsManagementProxy, self).__init__(*args, **kwargs)
250 self.root = root
251
252 @signal
253 def AuthorizationDenied(self, app_name):
254 """Signal thrown when the user denies the authorization."""
255
256 @signal
257 def CredentialsFound(self, app_name, credentials):
258 """Signal thrown when the credentials are found."""
259
260 @signal
261 def CredentialsNotFound(self, app_name):
262 """Signal thrown when the credentials are not found."""
263
264 @signal
265 def CredentialsCleared(self, app_name):
266 """Signal thrown when the credentials were cleared."""
267
268 @signal
269 def CredentialsStored(self, app_name):
270 """Signal thrown when the credentials were cleared."""
271
272 @signal
273 def CredentialsError(self, app_name, error_dict):
274 """Signal thrown when there is a problem getting the credentials."""
275
276 def find_credentials(self, app_name, args):
277 """Look for the credentials for an application.
278
279 - 'app_name': the name of the application which credentials are
280 going to be removed.
281
282 - 'args' is a dictionary, currently not used.
283
284 """
285 self.root.cred_manager.find_credentials(app_name, args)
286
287 def clear_credentials(self, app_name, args):
288 """Clear the credentials for an application.
289
290 - 'app_name': the name of the application which credentials are
291 going to be removed.
292
293 - 'args' is a dictionary, currently not used.
294
295 """
296 self.root.cred_manager.clear_credentials(app_name, args)
297
298 def store_credentials(self, app_name, args):
299 """Store the token for an application.
300
301 - 'app_name': the name of the application which credentials are
302 going to be stored.
303
304 - 'args' is the dictionary holding the credentials. Needs to provide
305 the following mandatory keys: 'token', 'token_key', 'consumer_key',
306 'consumer_secret'.
307
308 """
309 self.root.cred_manager.store_credentials(app_name, args)
310
311 def register(self, app_name, args):
312 """Get credentials if found else prompt GUI to register."""
313 self.root.cred_manager.register(app_name, args)
314
315 def login(self, app_name, args):
316 """Get credentials if found else prompt GUI to login."""
317 self.root.cred_manager.login(app_name, args)
318
319 def login_email_password(self, app_name, args):
320 """Get credentials if found, else login using email and password.
321
322 - 'args' should contain at least the follwing keys: 'email' and
323 'password'. Those will be used to issue a new SSO token, which will be
324 returned trough the CredentialsFound signal.
325
326 """
327 self.root.cred_manager.login_email_password(app_name, args)
328
329
330class UbuntuSSOProxy(BaseService):
331 """Object that exposes the diff referenceable objects."""93 """Object that exposes the diff referenceable objects."""
33294
333 services = {
334 'sso_login': SSOLoginProxy,
335 'cred_manager': CredentialsManagementProxy,
336 }
337
338 name = SSO_SERVICE_NAME95 name = SSO_SERVICE_NAME
33996
340 @property97 @property
341 def port(self):98 def port(self):
342 """Get the port of the remote service."""99 """Get the port on which the SSO pb is running."""
343 return get_sso_pb_port()100 return get_sso_pb_port()
344101
345 @property102 @property
346 def cmdline(self):103 def cmdline(self):
347 """Get the command line to run the service executable."""104 """Get the command line to activate an executable."""
348 return get_activation_cmdline(UbuntuSSOProxy.name)105 return get_activation_cmdline(self.name)
349
350
351# ============================== client classes ==============================
352
353
354class SSOLoginClient(RemoteClient):
355 """Client that can perform calls to the remote SSOLogin object."""
356
357 call_remote_functions = SSOLoginProxy.remote_calls
358 signal_handlers = [
359 'CaptchaGenerated',
360 'CaptchaGenerationError',
361 'UserRegistered',
362 'UserRegistrationError',
363 'LoggedIn',
364 'LoginError',
365 'UserNotValidated',
366 'EmailValidated',
367 'EmailValidationError',
368 'PasswordResetTokenSent',
369 'PasswordResetError',
370 'PasswordChanged',
371 'PasswordChangeError',
372 ]
373
374
375class CredentialsManagementClient(RemoteClient):
376 """Client that can perform calls to the remote CredManagement object."""
377
378 call_remote_functions = CredentialsManagementProxy.remote_calls
379 signal_handlers = [
380 'AuthorizationDenied',
381 'CredentialsFound',
382 'CredentialsNotFound',
383 'CredentialsCleared',
384 'CredentialsStored',
385 'CredentialsError',
386 ]
387106
388107
389class UbuntuSSOClient(BaseClient):108class UbuntuSSOClient(BaseClient):
390 """Base client that provides remote access to the sso API."""109 """Base client that provides remote access to the sso API."""
391110
111 name = SSO_SERVICE_NAME
112
392 clients = {113 clients = {
393 'sso_login': SSOLoginClient,114 'sso_login': SSOLoginClient,
394 'cred_manager': CredentialsManagementClient,115 'cred_manager': CredentialsManagementClient,
@@ -405,36 +126,3 @@
405 result = UbuntuSSOClient()126 result = UbuntuSSOClient()
406 yield result.connect()127 yield result.connect()
407 defer.returnValue(result)128 defer.returnValue(result)
408
409
410def add_timeout(interval, callback, *args, **kwargs):
411 """Add a timeout callback as a task."""
412 time_out_task = LoopingCall(callback, *args, **kwargs)
413 time_out_task.start(interval / 1000, now=False)
414
415
416timeout_func = add_timeout
417start_setup = lambda *a, **kw: None
418
419# the reactor does have run and stop methods
420# pylint: disable=E1101
421
422
423def shutdown_func():
424 """Stop the reactor."""
425 from twisted.internet import reactor
426 reactor.stop()
427
428
429def finish_setup(result, loop):
430 """Stop the reactor if a failure ocurred."""
431 if isinstance(result, Failure):
432 shutdown_func()
433
434
435def main():
436 """Run the specific mainloop."""
437 from twisted.internet import reactor
438 reactor.run()
439
440# pylint: enable=E1101
441129
=== modified file 'ubuntu_sso/networkstate/__init__.py'
--- ubuntu_sso/networkstate/__init__.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/networkstate/__init__.py 2012-04-27 15:54:20 +0000
@@ -1,5 +1,4 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2# Author: Manuel de la Pena <manuel@canonical.com>
3#2#
4# Copyright 2011-2012 Canonical Ltd.3# Copyright 2011-2012 Canonical Ltd.
5#4#
@@ -47,15 +46,16 @@
4746
48if sys.platform == 'win32':47if sys.platform == 'win32':
49 from ubuntu_sso.networkstate import windows48 from ubuntu_sso.networkstate import windows
50 NetworkManagerState = windows.NetworkManagerState49 networksource = windows
51 ONLINE = windows.ONLINE50elif sys.platform == 'darwin':
52 OFFLINE = windows.OFFLINE51 from ubuntu_sso.networkstate import darwin
53 UNKNOWN = windows.UNKNOWN52 networksource = darwin
54 is_machine_connected = windows.is_machine_connected
55else:53else:
56 from ubuntu_sso.networkstate import linux54 from ubuntu_sso.networkstate import linux
57 NetworkManagerState = linux.NetworkManagerState55 networksource = linux
58 ONLINE = linux.ONLINE56
59 OFFLINE = linux.OFFLINE57NetworkManagerState = networksource.NetworkManagerState
60 UNKNOWN = linux.UNKNOWN58ONLINE = networksource.ONLINE
61 is_machine_connected = linux.is_machine_connected59OFFLINE = networksource.OFFLINE
60UNKNOWN = networksource.UNKNOWN
61is_machine_connected = networksource.is_machine_connected
6262
=== added file 'ubuntu_sso/networkstate/darwin.py'
--- ubuntu_sso/networkstate/darwin.py 1970-01-01 00:00:00 +0000
+++ ubuntu_sso/networkstate/darwin.py 2012-04-27 15:54:20 +0000
@@ -0,0 +1,95 @@
1# -*- coding: utf-8 -*-
2#
3# Copyright 2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16"""Implementation of network state detection."""
17
18from twisted.internet import defer
19
20from ubuntu_sso.networkstate import NetworkFailException
21from ubuntu_sso.networkstate.networkstates import (
22 ONLINE, OFFLINE, UNKNOWN,
23
24 NM_STATE_CONNECTING_LIST,
25 NM_STATE_CONNECTED_LIST,
26 NM_STATE_DISCONNECTED_LIST,
27 )
28from ubuntu_sso.networkstate.networkstates import NM_STATE_CONNECTED_GLOBAL
29from ubuntu_sso.logger import setup_logging
30logger = setup_logging("ubuntu_sso.networkstate")
31
32
33class NetworkManagerState(object):
34 """All likely to change very soon."""
35
36 def __init__(self, result_cb):
37 """Initialize this instance with a result and error callbacks."""
38 self.result_cb = result_cb
39 self.state_signal = None
40
41 def call_result_cb(self, state):
42 """Return the state thru the result callback."""
43 self.result_cb(state)
44
45 def got_state(self, state):
46 """Not actually called by DBus when the state is retrieved from NM."""
47 if state in NM_STATE_CONNECTED_LIST:
48 self.call_result_cb(ONLINE)
49 elif state in NM_STATE_CONNECTING_LIST:
50 logger.debug("Currently connecting, waiting for signal")
51 else:
52 self.call_result_cb(OFFLINE)
53
54 def got_error(self, error):
55 """Not actually called by DBus when the state is retrieved from NM."""
56 logger.error("Error contacting NetworkManager: %s" % \
57 str(error))
58 self.call_result_cb(UNKNOWN)
59
60 def state_changed(self, state):
61 """Called when a signal is emmited by Network Manager."""
62 if int(state) in NM_STATE_CONNECTED_LIST:
63 self.call_result_cb(ONLINE)
64 elif int(state) in NM_STATE_DISCONNECTED_LIST:
65 self.call_result_cb(OFFLINE)
66 else:
67 logger.debug("Not yet connected: continuing to wait")
68
69 def find_online_state(self):
70 """Get the network state and return it thru the set callback."""
71 try:
72 self.state_changed(NM_STATE_CONNECTED_GLOBAL)
73 except Exception, e: # pylint: disable=W0703
74 self.got_error(e)
75
76
77def is_machine_connected():
78 """Return a deferred that when fired, returns if the machine is online."""
79 d = defer.Deferred()
80
81 def got_state(state):
82 """The state was retrieved from the Network Manager."""
83 result = int(state) in NM_STATE_CONNECTED_LIST
84 d.callback(result)
85
86 # pylint: disable=W0702, W0703
87 try:
88 network = NetworkManagerState(got_state)
89 network.find_online_state()
90 except Exception, e:
91 logger.exception('is_machine_connected failed with:')
92 d.errback(NetworkFailException(e))
93 # pylint: enable=W0702, W0703
94
95 return d
096
=== modified file 'ubuntu_sso/networkstate/linux.py'
--- ubuntu_sso/networkstate/linux.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/networkstate/linux.py 2012-04-27 15:54:20 +0000
@@ -1,9 +1,5 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2#2#
3# networkstate - detect the current state of the network
4#
5# Author: Alejandro J. Cura <alecu@canonical.com>
6#
7# Copyright 2010-2012 Canonical Ltd.3# Copyright 2010-2012 Canonical Ltd.
8#4#
9# This program is free software: you can redistribute it and/or modify it5# This program is free software: you can redistribute it and/or modify it
@@ -37,44 +33,16 @@
37from twisted.internet import defer33from twisted.internet import defer
3834
39from ubuntu_sso.networkstate import NetworkFailException35from ubuntu_sso.networkstate import NetworkFailException
36from ubuntu_sso.networkstate.networkstates import (
37 ONLINE, OFFLINE, UNKNOWN,
38
39 NM_STATE_CONNECTING_LIST,
40 NM_STATE_CONNECTED_LIST,
41 NM_STATE_DISCONNECTED_LIST,
42 )
40from ubuntu_sso.logger import setup_logging43from ubuntu_sso.logger import setup_logging
41logger = setup_logging("ubuntu_sso.networkstate")44logger = setup_logging("ubuntu_sso.networkstate")
4245
43# Values returned by the callback
44ONLINE, OFFLINE, UNKNOWN = object(), object(), object()
45
46NM_STATE_NAMES = {
47 ONLINE: "online",
48 OFFLINE: "offline",
49 UNKNOWN: "unknown",
50}
51
52# Internal NetworkManager State constants
53NM_STATE_UNKNOWN = 0
54NM_STATE_UNKNOWN_LIST = [NM_STATE_UNKNOWN]
55NM_STATE_ASLEEP_OLD = 1
56NM_STATE_ASLEEP = 10
57NM_STATE_ASLEEP_LIST = [NM_STATE_ASLEEP_OLD,
58 NM_STATE_ASLEEP]
59NM_STATE_CONNECTING_OLD = 2
60NM_STATE_CONNECTING = 40
61NM_STATE_CONNECTING_LIST = [NM_STATE_CONNECTING_OLD,
62 NM_STATE_CONNECTING]
63NM_STATE_CONNECTED_OLD = 3
64NM_STATE_CONNECTED_LOCAL = 50
65NM_STATE_CONNECTED_SITE = 60
66NM_STATE_CONNECTED_GLOBAL = 70
67# Specifically don't include local and site, as they won't let us get to server
68NM_STATE_CONNECTED_LIST = [NM_STATE_CONNECTED_OLD,
69 NM_STATE_CONNECTED_GLOBAL]
70NM_STATE_DISCONNECTED_OLD = 4
71NM_STATE_DISCONNECTED = 20
72# For us, local and site connections are the same as diconnected
73NM_STATE_DISCONNECTED_LIST = [NM_STATE_DISCONNECTED_OLD,
74 NM_STATE_DISCONNECTED,
75 NM_STATE_CONNECTED_LOCAL,
76 NM_STATE_CONNECTED_SITE]
77
78NM_DBUS_INTERFACE = "org.freedesktop.NetworkManager"46NM_DBUS_INTERFACE = "org.freedesktop.NetworkManager"
79NM_DBUS_OBJECTPATH = "/org/freedesktop/NetworkManager"47NM_DBUS_OBJECTPATH = "/org/freedesktop/NetworkManager"
80DBUS_UNKNOWN_SERVICE = "org.freedesktop.DBus.Error.ServiceUnknown"48DBUS_UNKNOWN_SERVICE = "org.freedesktop.DBus.Error.ServiceUnknown"
8149
=== added file 'ubuntu_sso/networkstate/networkstates.py'
--- ubuntu_sso/networkstate/networkstates.py 1970-01-01 00:00:00 +0000
+++ ubuntu_sso/networkstate/networkstates.py 2012-04-27 15:54:20 +0000
@@ -0,0 +1,51 @@
1# -*- coding: utf-8 -*-
2#
3# Copyright 2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16"""Network states."""
17
18# Values returned by the callback
19ONLINE, OFFLINE, UNKNOWN = object(), object(), object()
20
21NM_STATE_NAMES = {
22 ONLINE: "online",
23 OFFLINE: "offline",
24 UNKNOWN: "unknown",
25}
26
27# Internal NetworkManager State constants
28NM_STATE_UNKNOWN = 0
29NM_STATE_UNKNOWN_LIST = [NM_STATE_UNKNOWN]
30NM_STATE_ASLEEP_OLD = 1
31NM_STATE_ASLEEP = 10
32NM_STATE_ASLEEP_LIST = [NM_STATE_ASLEEP_OLD,
33 NM_STATE_ASLEEP]
34NM_STATE_CONNECTING_OLD = 2
35NM_STATE_CONNECTING = 40
36NM_STATE_CONNECTING_LIST = [NM_STATE_CONNECTING_OLD,
37 NM_STATE_CONNECTING]
38NM_STATE_CONNECTED_OLD = 3
39NM_STATE_CONNECTED_LOCAL = 50
40NM_STATE_CONNECTED_SITE = 60
41NM_STATE_CONNECTED_GLOBAL = 70
42# Specifically don't include local and site, as they won't let us get to server
43NM_STATE_CONNECTED_LIST = [NM_STATE_CONNECTED_OLD,
44 NM_STATE_CONNECTED_GLOBAL]
45NM_STATE_DISCONNECTED_OLD = 4
46NM_STATE_DISCONNECTED = 20
47# For us, local and site connections are the same as diconnected
48NM_STATE_DISCONNECTED_LIST = [NM_STATE_DISCONNECTED_OLD,
49 NM_STATE_DISCONNECTED,
50 NM_STATE_CONNECTED_LOCAL,
51 NM_STATE_CONNECTED_SITE]
052
=== modified file 'ubuntu_sso/networkstate/tests/test_linux.py'
--- ubuntu_sso/networkstate/tests/test_linux.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/networkstate/tests/test_linux.py 2012-04-27 15:54:20 +0000
@@ -1,9 +1,5 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2#2#
3# test_networkstate - tests for ubuntu_sso.networkstate
4#
5# Author: Alejandro J. Cura <alecu@canonical.com>
6#
7# Copyright 2010-2012 Canonical Ltd.3# Copyright 2010-2012 Canonical Ltd.
8#4#
9# This program is free software: you can redistribute it and/or modify it5# This program is free software: you can redistribute it and/or modify it
@@ -42,13 +38,10 @@
42 linux,38 linux,
43 NetworkFailException,39 NetworkFailException,
44 NetworkManagerState,40 NetworkManagerState,
41)
42
43from ubuntu_sso.networkstate.networkstates import (
45 ONLINE, OFFLINE, UNKNOWN,44 ONLINE, OFFLINE, UNKNOWN,
46)
47
48from ubuntu_sso.networkstate.linux import (is_machine_connected,
49 DBUS_UNKNOWN_SERVICE,
50 NM_DBUS_INTERFACE,
51 NM_DBUS_OBJECTPATH,
52 NM_STATE_ASLEEP,45 NM_STATE_ASLEEP,
53 NM_STATE_ASLEEP_OLD,46 NM_STATE_ASLEEP_OLD,
54 NM_STATE_CONNECTING,47 NM_STATE_CONNECTING,
@@ -62,6 +55,12 @@
62 NM_STATE_UNKNOWN,55 NM_STATE_UNKNOWN,
63)56)
6457
58from ubuntu_sso.networkstate.linux import (is_machine_connected,
59 DBUS_UNKNOWN_SERVICE,
60 NM_DBUS_INTERFACE,
61 NM_DBUS_OBJECTPATH,
62)
63
6564
66class TestException(Exception):65class TestException(Exception):
67 """An exception to test error conditions."""66 """An exception to test error conditions."""
6867
=== modified file 'ubuntu_sso/qt/__init__.py'
--- ubuntu_sso/qt/__init__.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/qt/__init__.py 2012-04-27 15:54:20 +0000
@@ -28,6 +28,7 @@
28# files in the program, then also delete it here.28# files in the program, then also delete it here.
29"""The Qt graphical interface for the Ubuntu Single Sign On Client."""29"""The Qt graphical interface for the Ubuntu Single Sign On Client."""
3030
31import sys
31import collections32import collections
3233
33from PyQt4 import QtGui, QtCore34from PyQt4 import QtGui, QtCore
@@ -46,6 +47,12 @@
46TITLE_STYLE = u'<span style="font-size:xx-large;font-weight:bold;">%s</span>'47TITLE_STYLE = u'<span style="font-size:xx-large;font-weight:bold;">%s</span>'
47WINDOW_TITLE = 'Ubuntu Single Sign On'48WINDOW_TITLE = 'Ubuntu Single Sign On'
4849
50# TODO: There is a pixel discrepancy between Qt on Linux and Windows
51# and Mac OS X. On Mac OS X, one test fails with the height being
52# off. For now, we're forcing a different UI height on darwin.
53if sys.platform == 'darwin':
54 PREFERED_UI_SIZE['height'] = 533
55
4956
50# Based on the gtk implementation57# Based on the gtk implementation
51def build_general_error_message(errordict):58def build_general_error_message(errordict):
5259
=== modified file 'ubuntu_sso/qt/main/__init__.py'
--- ubuntu_sso/qt/main/__init__.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/qt/main/__init__.py 2012-04-27 15:54:20 +0000
@@ -41,7 +41,7 @@
4141
4242
43# Invalid name "source", pylint: disable=C010343# Invalid name "source", pylint: disable=C0103
44if sys.platform == 'win32':44if sys.platform in ('win32', 'darwin'):
45 from ubuntu_sso.qt.main import windows45 from ubuntu_sso.qt.main import windows
46 source = windows46 source = windows
47else:47else:
4848
=== modified file 'ubuntu_sso/utils/__init__.py'
--- ubuntu_sso/utils/__init__.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/utils/__init__.py 2012-04-27 15:54:20 +0000
@@ -47,11 +47,13 @@
47BIN_SUFFIX = 'bin'47BIN_SUFFIX = 'bin'
48DATA_SUFFIX = 'data'48DATA_SUFFIX = 'data'
4949
50if sys.platform == "win32":50QSS_MAP = dict(win32=':/windows.qss',
51 from ubuntu_sso.utils import windows as source51 darwin=':/darwin.qss',
52else:52 linux=':/linux.qss')
53 from ubuntu_sso.utils import linux as source53
54PLATFORM_QSS = source.PLATFORM_QSS54# Setting linux as default if we don't find the
55# platform as a key in the dictionary
56PLATFORM_QSS = QSS_MAP.get(sys.platform, ":/linux.qss")
5557
5658
57def _get_dir(dir_name, dir_constant):59def _get_dir(dir_name, dir_constant):
@@ -72,7 +74,8 @@
7274
73 # otherwise, try to load 'dir_constant' from installation path75 # otherwise, try to load 'dir_constant' from installation path
74 try:76 try:
75 # Unused variable 'ubuntu_sso', pylint: disable=W0612, F0401, E061177 # Unused variable 'ubuntu_sso'
78 # pylint: disable=W0612, F0401, E0611
76 import ubuntu_sso.constants79 import ubuntu_sso.constants
77 module = sys.modules.get('ubuntu_sso.constants')80 module = sys.modules.get('ubuntu_sso.constants')
78 return getattr(module, dir_constant)81 return getattr(module, dir_constant)
7982
=== removed file 'ubuntu_sso/utils/linux.py'
--- ubuntu_sso/utils/linux.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/utils/linux.py 1970-01-01 00:00:00 +0000
@@ -1,31 +0,0 @@
1# -*- coding: utf-8 -*-
2#
3# Copyright 2010-2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# In addition, as a special exception, the copyright holders give
18# permission to link the code of portions of this program with the
19# OpenSSL library under certain conditions as described in each
20# individual source file, and distribute linked combinations
21# including the two.
22# You must obey the GNU General Public License in all respects
23# for all of the code used other than OpenSSL. If you modify
24# file(s) with this exception, you may extend this exception to your
25# version of the file(s), but you are not obligated to do so. If you
26# do not wish to do so, delete this exception statement from your
27# version. If you delete this exception statement from all source
28# files in the program, then also delete it here.
29"""Platform specific constants and functions (for Linux)."""
30
31PLATFORM_QSS = ":/linux.qss"
320
=== renamed file 'ubuntu_sso/utils/windows.py' => 'ubuntu_sso/utils/qtwisted.py'
--- ubuntu_sso/utils/windows.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/utils/qtwisted.py 2012-04-27 15:54:20 +0000
@@ -26,9 +26,7 @@
26# do not wish to do so, delete this exception statement from your26# do not wish to do so, delete this exception statement from your
27# version. If you delete this exception statement from all source27# version. If you delete this exception statement from all source
28# files in the program, then also delete it here.28# files in the program, then also delete it here.
29"""Platform specific constants and functions (for Windows)."""29"""Platform specific constants and functions (for Qt/Twisted)."""
30
31PLATFORM_QSS = ":/windows.qss"
3230
33from twisted.internet import defer31from twisted.internet import defer
34from PyQt4.QtCore import QThread, QCoreApplication32from PyQt4.QtCore import QThread, QCoreApplication
3533
=== renamed file 'ubuntu_sso/utils/tests/test_windows.py' => 'ubuntu_sso/utils/tests/test_qtwisted.py'
--- ubuntu_sso/utils/tests/test_windows.py 2012-04-09 17:38:24 +0000
+++ ubuntu_sso/utils/tests/test_qtwisted.py 2012-04-27 15:54:20 +0000
@@ -33,7 +33,7 @@
33from twisted.internet import defer33from twisted.internet import defer
34from twisted.trial.unittest import TestCase34from twisted.trial.unittest import TestCase
3535
36from ubuntu_sso.utils.windows import qtDeferToThread36from ubuntu_sso.utils.qtwisted import qtDeferToThread
3737
3838
39class FakeException(Exception):39class FakeException(Exception):

Subscribers

People subscribed via source and target branches