def connect(self):
        self.anomaly_tracker = AnomalyTracker(now())

        if self.current_printer().is_authenticated:
            self.accept()
            async_to_sync(self.channel_layer.group_add)(
                channels.octo_group_name(self.current_printer().id),
                self.channel_name)
            self.last_touch = time.time()
            Room.objects.add(
                channels.octo_group_name(self.current_printer().id),
                self.channel_name)
            # Send remote status to OctoPrint as soon as it connects
            self.printer_message({
                'remote_status': {
                    'viewing':
                    channels.num_ws_connections(
                        channels.web_group_name(self.current_printer().id)) >
                    0,
                    'should_watch':
                    self.current_printer().should_watch(),
                }
            })
        else:
            self.close()
Esempio n. 2
0
    def connect(self):
        self.anomaly_tracker = AnomalyTracker(now())
        self.printer = None

        self.printer = self.get_printer()

        self.accept()

        async_to_sync(self.channel_layer.group_add)(channels.octo_group_name(
            self.printer.id), self.channel_name)

        self.last_touch = time.time()

        Room.objects.add(channels.octo_group_name(self.printer.id),
                         self.channel_name)

        # Send remote status to OctoPrint as soon as it connects
        self.printer_message({
            'remote_status': {
                'viewing':
                channels.num_ws_connections(
                    channels.web_group_name(self.printer.id)) > 0,
                'should_watch':
                self.printer.should_watch(),
            }
        })

        touch_user_last_active(self.printer.user)
 def is_octoprint_connected(self):
     return channels.num_ws_connections(
         channels.octo_group_name(self.printer.id)
     ) > 0
def _octoprint_http_tunnel(request, octoprinttunnel):
    user = octoprinttunnel.printer.user
    if user.tunnel_usage_over_cap():
        return HttpResponse(OVER_FREE_LIMIT_HTML,
                            status=OVER_FREE_LIMIT_STATUS_CODE)

    # if plugin is disconnected, halt
    if channels.num_ws_connections(
            channels.octo_group_name(octoprinttunnel.printer.id)) < 1:
        return HttpResponse(NOT_CONNECTED_HTML,
                            status=NOT_CONNECTED_STATUS_CODE)

    version = (cache.printer_settings_get(octoprinttunnel.printer.pk)
               or {}).get('tsd_plugin_version', '')
    is_v1 = version and not is_plugin_version_supported(version)
    if is_v1:
        return HttpResponse(NOT_CONNECTED_HTML,
                            status=NOT_CONNECTED_STATUS_CODE)

    method = request.method.lower()
    path = request.get_full_path()

    IGNORE_HEADERS = [
        'HTTP_HOST',
        'HTTP_ORIGIN',
        'HTTP_REFERER',  # better not to tell
        'HTTP_AUTHORIZATION',  # handled explicitely
        'HTTP_COOKIE',  # handled explicitely
        'HTTP_ACCEPT_ENCODING',  # should be handled by TSD server
    ]

    req_headers = {
        k[5:].replace('_', ' ').title().replace(' ', '-'): v
        for (k, v) in request.META.items()
        if (k.startswith('HTTP') and k not in IGNORE_HEADERS
            and not k.startswith('HTTP_X_FORWARDED')  # meant for TSD server
            )
    }

    if 'CONTENT_TYPE' in request.META:
        req_headers['Content-Type'] = request.META['CONTENT_TYPE']

    if 'HTTP_COOKIE' in request.META:
        # let's not forward cookies of TSD server
        stripped_cookies = '; '.join([
            cookie.strip() for cookie in request.META['HTTP_COOKIE'].split(';')
            if DJANGO_COOKIE_RE.match(cookie.strip()) is None
        ])
        if stripped_cookies:
            req_headers['Cookie'] = stripped_cookies

    if hasattr(request, 'auth_header'):
        # let's not forward basic auth header of external tunnel
        stripped_auth_heaader = ', '.join([
            h for h in request.META['HTTP_AUTHORIZATION'].split(',')
            if h != request.auth_header
        ])
        if stripped_auth_heaader:
            req_headers['Authorization'] = stripped_auth_heaader

    ref = f'v2.{octoprinttunnel.id}.{method}.{time.time()}.{path}'

    channels.send_msg_to_printer(
        octoprinttunnel.printer.id, {
            'http.tunnelv2': {
                'ref': ref,
                'method': method,
                'headers': req_headers,
                'path': path,
                'data': request.body
            },
            'as_binary': True,
        })

    data = cache.octoprinttunnel_http_response_get(ref)
    if data is None:
        # request timed out
        return HttpResponse(NOT_CONNECTED_HTML, status=TIMED_OUT_STATUS_CODE)

    content_type = data['response']['headers'].get('Content-Type') or None
    status_code = data['response']['status']

    resp = HttpResponse(
        status=status_code,
        content_type=content_type,
    )

    to_ignore = (
        'content-length',  # set by django
        'content-encoding',  # if its set, it is probably incorrect/unapplicable
        'x-frame-options',  # response must load in TSD's iframe
    )
    for k, v in data['response']['headers'].items():
        if k.lower() in to_ignore:
            continue

        if k.lower() == 'etag':
            # pre 1.6.? octoprint has invalid etag format for some responses
            v = fix_etag(v)

        resp[k] = v

    # plugin connects over http to octoprint,
    # but TSD needs cookies working over https.
    # without this, cookies set in response might not be used
    # in some browsers (FF gives wwarning)
    for cookie in (data['response'].get('cookies', ()) or ()):
        if (request.is_secure() and 'secure' not in cookie.lower()):
            cookie += '; Secure'

        if 'Expires=' not in cookie and 'Max-Age=' not in cookie:
            cookie += '; Max-Age=7776000'  # 3 months

        resp['Set-Cookie'] = cookie

    if data['response'].get('compressed', False):
        content = zlib.decompress(data['response']['content'])
    else:
        content = data['response']['content']

    cache.octoprinttunnel_update_stats(user.id, len(content))

    resp.write(content)
    return resp