예제 #1
0
class InviteReceiver(QObject):

    # Wormhole
    got_welcome = Signal(dict)
    # got_code = Signal(str)
    got_introduction = Signal()
    got_message = Signal(dict)
    closed = Signal()

    # SetupRunner
    grid_already_joined = Signal(str)
    update_progress = Signal(str)
    got_icon = Signal(str)
    client_started = Signal(object)
    joined_folders = Signal(list)
    done = Signal(object)

    def __init__(self, known_gateways=None, use_tor=False):
        super(InviteReceiver, self).__init__()
        self.known_gateways = known_gateways
        self.use_tor = use_tor

        self.setup_runner = SetupRunner(known_gateways, use_tor)
        self.setup_runner.grid_already_joined.connect(
            self.grid_already_joined.emit
        )
        self.setup_runner.update_progress.connect(self.update_progress.emit)
        self.setup_runner.got_icon.connect(self.got_icon.emit)
        self.setup_runner.client_started.connect(self.client_started.emit)
        self.setup_runner.joined_folders.connect(self.joined_folders.emit)
        self.setup_runner.done.connect(self.done.emit)

        self.wormhole = Wormhole(use_tor)
        self.wormhole.got_welcome.connect(self.got_welcome.emit)
        self.wormhole.got_introduction.connect(self.got_introduction.emit)
        self.wormhole.got_message.connect(self.got_message.emit)
        self.wormhole.closed.connect(self.closed.emit)

    def cancel(self):
        self.wormhole.close()

    @inlineCallbacks
    def _run_setup(self, settings, from_wormhole):
        settings = validate_settings(
            settings, self.known_gateways, None, from_wormhole
        )
        yield self.setup_runner.run(settings)

    @inlineCallbacks
    def receive(self, code, settings=None):
        # TODO: Calculate/emit total steps
        if settings:
            yield self._run_setup(settings, from_wormhole=False)
        elif code.split("-")[0] == "0":
            settings = load_settings_from_cheatcode(code[2:])
            if settings:
                yield self._run_setup(settings, from_wormhole=False)
        else:
            settings = yield self.wormhole.receive(code)
            yield self._run_setup(settings, from_wormhole=True)
예제 #2
0
def test_wormhole_receive_via_xfer_util(qtbot, monkeypatch):
    fake_wormhole = MagicMock()
    fake_wormhole.get_welcome.return_value = {}
    fake_wormhole.get_message.return_value = (
        b'{"offer": {"message": "{\\"nickname\\": \\"Test Grid\\"}"}}')
    monkeypatch.setattr("gridsync.wormhole_.wormhole.create",
                        lambda x, y, z: fake_wormhole)
    wormhole = Wormhole()
    output = yield wormhole.receive("123-test-test")
    assert output == {"nickname": "Test Grid"}
예제 #3
0
def test_wormhole_receive_succeed_return_msg_dict(qtbot, monkeypatch):
    fake_wormhole = MagicMock()
    fake_wormhole.get_welcome.return_value = {}
    fake_wormhole.get_message.return_value = (
        b'{"abilities": {"server-v1": {}}}')
    monkeypatch.setattr("gridsync.wormhole_.wormhole.create",
                        lambda x, y, z: fake_wormhole)
    wormhole = Wormhole()
    output = yield wormhole.receive("123-test-test")
    assert output == {"abilities": {"server-v1": {}}}
예제 #4
0
def test_wormhole_receive_raise_upgrade_required_no_abilities(
        qtbot, monkeypatch):
    fake_wormhole = MagicMock()
    fake_wormhole.get_welcome.return_value = {}
    fake_wormhole.get_message.return_value = b'{"blah": "blah"}'
    monkeypatch.setattr("gridsync.wormhole_.wormhole.create",
                        lambda x, y, z: fake_wormhole)
    wormhole = Wormhole()
    with pytest.raises(UpgradeRequiredError):
        yield wormhole.receive("123-test-test")
예제 #5
0
def test_wormhole_receive_emit_got_introduction_signal(qtbot, monkeypatch):
    fake_wormhole = MagicMock()
    fake_wormhole.get_welcome.return_value = {}
    fake_wormhole.get_message.return_value = (
        b'{"abilities": {"server-v1": {}}}')
    monkeypatch.setattr("gridsync.wormhole_.wormhole.create",
                        lambda x, y, z: fake_wormhole)
    wormhole = Wormhole()
    with qtbot.wait_signal(wormhole.got_introduction):
        yield wormhole.receive("123-test-test")
예제 #6
0
def test_wormhole_receive_succeed_emit_got_message_signal(qtbot, monkeypatch):
    fake_wormhole = MagicMock()
    fake_wormhole.get_welcome.return_value = {}
    fake_wormhole.get_message.return_value = (
        b'{"offer": {"message": "{\\"nickname\\": \\"Test Grid\\"}"}}')
    monkeypatch.setattr("gridsync.wormhole_.wormhole.create",
                        lambda x, y, z: fake_wormhole)
    wormhole = Wormhole()
    with qtbot.wait_signal(wormhole.got_message) as blocker:
        yield wormhole.receive("123-test-test")
    assert blocker.args == [{"nickname": "Test Grid"}]
예제 #7
0
def test_wormhole_receive_raise_upgrade_required_bad_version(
        qtbot, monkeypatch):
    fake_wormhole = MagicMock()
    fake_wormhole.get_welcome.return_value = {}
    fake_wormhole.get_message.return_value = (
        b'{"abilities": {"server-v9999": {}}}')
    monkeypatch.setattr("gridsync.wormhole_.wormhole.create",
                        lambda x, y, z: fake_wormhole)
    wormhole = Wormhole()
    with pytest.raises(UpgradeRequiredError):
        yield wormhole.receive("123-test-test")
예제 #8
0
def test_wormhole_receive_via_xfer_util_raise_unknown_offer(
        qtbot, monkeypatch):
    fake_wormhole = MagicMock()
    fake_wormhole.get_welcome.return_value = {}
    fake_wormhole.get_message.return_value = (
        b'{"offer": {"NOT_message": "{\\"nickname\\": \\"Test Grid\\"}"}}')
    monkeypatch.setattr("gridsync.wormhole_.wormhole.create",
                        lambda x, y, z: fake_wormhole)
    wormhole = Wormhole()
    with pytest.raises(Exception):
        yield wormhole.receive("123-test-test")
예제 #9
0
class InviteReceiver(QDialog):
    done = pyqtSignal(QWidget)
    closed = pyqtSignal(QWidget)

    def __init__(self, gateways):
        super(InviteReceiver, self).__init__()
        self.gateways = gateways
        self.wormhole = None
        self.setup_runner = None
        self.joined_folders = []
        self.use_tor = False

        self.setMinimumSize(500, 300)

        self.mail_closed_icon = QLabel()
        self.mail_closed_icon.setPixmap(
            QPixmap(resource('mail-envelope-closed.png')).scaled(128, 128))
        self.mail_closed_icon.setAlignment(Qt.AlignCenter)

        self.mail_open_icon = QLabel()
        self.mail_open_icon.setPixmap(
            QPixmap(resource('mail-envelope-open.png')).scaled(128, 128))
        self.mail_open_icon.setAlignment(Qt.AlignCenter)

        self.folder_icon = QLabel()
        icon = QFileIconProvider().icon(QFileInfo(config_dir))
        self.folder_icon.setPixmap(icon.pixmap(128, 128))
        self.folder_icon.setAlignment(Qt.AlignCenter)

        self.invite_code_widget = InviteCodeWidget(self)
        self.label = self.invite_code_widget.label
        self.tor_checkbox = self.invite_code_widget.checkbox
        self.tor_checkbox.stateChanged.connect(self.on_checkbox_state_changed)
        self.lineedit = self.invite_code_widget.lineedit
        self.lineedit.error.connect(self.show_error)
        self.lineedit.go.connect(self.go)

        self.tor_label = QLabel()
        self.tor_label.setToolTip(
            "This connection is being routed through the Tor network.")
        self.tor_label.setPixmap(
            QPixmap(resource('tor-onion.png')).scaled(32, 32))

        self.progressbar = QProgressBar(self)
        self.progressbar.setValue(0)
        self.progressbar.setMaximum(6)  # XXX
        self.progressbar.setTextVisible(False)

        self.message_label = QLabel()
        self.message_label.setStyleSheet("color: grey")
        self.message_label.setAlignment(Qt.AlignCenter)

        self.error_label = QLabel()
        self.error_label.setStyleSheet("color: red")
        self.error_label.setAlignment(Qt.AlignCenter)

        self.close_button = QPushButton("Close")
        self.close_button.clicked.connect(self.close)

        layout = QGridLayout(self)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 0, 0)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 1)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 2)
        layout.addWidget(self.mail_closed_icon, 1, 2, 1, 3)
        layout.addWidget(self.mail_open_icon, 1, 2, 1, 3)
        layout.addWidget(self.folder_icon, 1, 2, 1, 3)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 4)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 5)
        layout.addWidget(self.label, 2, 3, 1, 1)
        layout.addWidget(self.tor_label, 3, 1, 1, 1,
                         Qt.AlignRight | Qt.AlignVCenter)
        layout.addWidget(self.lineedit, 3, 2, 1, 3)
        layout.addWidget(self.progressbar, 3, 2, 1, 3)
        layout.addWidget(self.tor_checkbox, 4, 2, 1, 3, Qt.AlignCenter)
        layout.addWidget(self.message_label, 5, 1, 1, 5)
        layout.addWidget(self.error_label, 5, 2, 1, 3)
        layout.addWidget(self.close_button, 6, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 7, 1)

        self.reset()

    def reset(self):
        self.mail_open_icon.hide()
        self.folder_icon.hide()
        self.mail_closed_icon.show()
        self.label.setText("Enter invite code:")
        self.lineedit.show()
        self.lineedit.setText('')
        self.tor_checkbox.show()
        self.progressbar.hide()
        self.message_label.setText(
            "Invite codes can be used to join a grid or a folder")
        self.error_label.setText('')
        self.error_label.hide()
        self.close_button.hide()
        self.tor_label.hide()

    def on_checkbox_state_changed(self, state):
        self.use_tor = bool(state)
        logging.debug("use_tor=%s", self.use_tor)
        if state:
            self.progressbar.setStyleSheet(
                'QProgressBar::chunk {{ background-color: {}; }}'.format(
                    TOR_PURPLE))
        else:
            self.progressbar.setStyleSheet('')

    def show_error(self, text):
        self.error_label.setText(text)
        self.message_label.hide()
        self.error_label.show()
        reactor.callLater(3, self.error_label.hide)
        reactor.callLater(3, self.message_label.show)

    def update_progress(self, message):
        step = self.progressbar.value() + 1
        self.progressbar.setValue(step)
        self.message_label.setText(message)
        if step == 3:
            self.mail_closed_icon.hide()
            self.mail_open_icon.show()
        if step == 4:
            self.mail_open_icon.hide()
            self.folder_icon.show()

    def set_joined_folders(self, folders):
        self.joined_folders = folders

    def on_done(self, _):
        self.progressbar.setValue(self.progressbar.maximum())
        self.close_button.show()
        self.done.emit(self)
        self.label.setPixmap(
            QPixmap(resource('green_checkmark.png')).scaled(32, 32))
        if self.joined_folders and len(self.joined_folders) == 1:
            target = self.joined_folders[0]
            self.message_label.setText(
                'Successfully joined folder "{0}"!\n"{0}" is now available '
                'for download'.format(target))
        elif self.joined_folders:
            target = humanized_list(self.joined_folders, 'folders')
            self.message_label.setText(
                'Successfully joined {0}!\n{0} are now available for '
                'download'.format(target))

    def on_grid_already_joined(self, grid_name):
        QMessageBox.information(
            self, "Already connected",
            'You are already connected to "{}"'.format(grid_name))
        self.close()

    def got_message(self, message):
        self.update_progress("Reading invitation...")  # 3
        message = validate_settings(message, self.gateways, self)
        self.setup_runner = SetupRunner(self.gateways, self.use_tor)
        if not message.get('magic-folders'):
            self.setup_runner.grid_already_joined.connect(
                self.on_grid_already_joined)
        self.setup_runner.update_progress.connect(self.update_progress)
        self.setup_runner.joined_folders.connect(self.set_joined_folders)
        self.setup_runner.done.connect(self.on_done)
        self.setup_runner.run(message)

    def got_welcome(self):
        self.update_progress("Connected; waiting for message...")  # 2

    def handle_failure(self, failure):
        logging.error(str(failure))
        if failure.type == CancelledError and self.progressbar.value() > 2:
            return
        show_failure(failure, self)
        self.close()

    def go(self, code):
        self.reset()
        self.label.setText(' ')
        self.lineedit.hide()
        self.tor_checkbox.hide()
        self.progressbar.show()
        if self.use_tor:
            self.tor_label.show()
        self.update_progress("Verifying invitation...")  # 1
        if code.split('-')[0] == "0":
            settings = get_settings_from_cheatcode(code[2:])
            if settings:
                self.got_message(settings)
                return
        self.wormhole = Wormhole(self.use_tor)
        self.wormhole.got_welcome.connect(self.got_welcome)
        self.wormhole.got_message.connect(self.got_message)
        d = self.wormhole.receive(code)
        d.addErrback(self.handle_failure)
        reactor.callLater(30, d.cancel)

    def enterEvent(self, event):
        event.accept()
        self.lineedit.update_action_button()

    def closeEvent(self, event):
        event.accept()
        try:
            self.wormhole.close()
        except AttributeError:
            pass
        self.closed.emit(self)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.close()